diff --git a/.gitignore b/.gitignore index 6e422dc..a2ce5d6 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,6 @@ .DS_Store bgdocs.code-workspace +node_modules + diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..52e093f --- /dev/null +++ b/.gitmodules @@ -0,0 +1,4 @@ + +[submodule "doc-site/themes/docsy"] + path = doc-site/themes/docsy + url = https://github.com/google/docsy diff --git a/doc-site/.github/dependabot.yml b/doc-site/.github/dependabot.yml new file mode 100644 index 0000000..573e2f0 --- /dev/null +++ b/doc-site/.github/dependabot.yml @@ -0,0 +1,14 @@ +version: 2 +updates: +- package-ecosystem: npm + directory: "/" + schedule: + interval: daily + time: '20:00' + open-pull-requests-limit: 10 +- package-ecosystem: bundler + directory: "/" + schedule: + interval: daily + time: '20:00' + open-pull-requests-limit: 10 diff --git a/doc-site/.gitignore b/doc-site/.gitignore new file mode 100644 index 0000000..8afd9f0 --- /dev/null +++ b/doc-site/.gitignore @@ -0,0 +1,6 @@ +/public +resources/ +node_modules/ +package-lock.json +.hugo_build.lock +*.bak diff --git a/doc-site/.nvmrc b/doc-site/.nvmrc new file mode 100644 index 0000000..b009dfb --- /dev/null +++ b/doc-site/.nvmrc @@ -0,0 +1 @@ +lts/* diff --git a/doc-site/Dockerfile b/doc-site/Dockerfile new file mode 100644 index 0000000..f28f7b6 --- /dev/null +++ b/doc-site/Dockerfile @@ -0,0 +1,3 @@ +FROM klakegg/hugo:ext-alpine + +RUN apk add git diff --git a/doc-site/assets/scss/_variables_project.scss b/doc-site/assets/scss/_variables_project.scss new file mode 100644 index 0000000..2569027 --- /dev/null +++ b/doc-site/assets/scss/_variables_project.scss @@ -0,0 +1,6 @@ +/* + +Add styles or override variables from the theme here. + +*/ + diff --git a/doc-site/config.toml b/doc-site/config.toml new file mode 100644 index 0000000..e2a7e69 --- /dev/null +++ b/doc-site/config.toml @@ -0,0 +1,233 @@ +baseURL = "https://yahoo.github.io/bgdocs/docs/typescript/" +title = "Behavior Graph" + +ignoreFiles = ["community", "blog", "about", "docs2", "ignore", "\\.bak$"] + +enableRobotsTXT = true + +# Hugo allows theme composition (and inheritance). The precedence is from left to right. +theme = ["docsy"] + +# Will give values to .Lastmod etc. +enableGitInfo = true + +# Language settings +contentDir = "content/en" +defaultContentLanguage = "en" +defaultContentLanguageInSubdir = false +# Useful when translating. +enableMissingTranslationPlaceholders = true + +# Comment out to enable taxonomies in Docsy +# disableKinds = ["taxonomy", "taxonomyTerm"] + +# You can add your own taxonomies +[taxonomies] +tag = "tags" +category = "categories" + +[params.taxonomy] +# set taxonomyCloud = [] to hide taxonomy clouds +taxonomyCloud = ["tags", "categories"] + +# If used, must have same lang as taxonomyCloud +taxonomyCloudTitle = ["Tag Cloud", "Categories"] + +# set taxonomyPageHeader = [] to hide taxonomies on the page headers +taxonomyPageHeader = ["tags", "categories"] + + +# Highlighting config +pygmentsCodeFences = true +pygmentsUseClasses = false +# Use the new Chroma Go highlighter in Hugo. +pygmentsUseClassic = false +#pygmentsOptions = "linenos=table" +# See https://help.farbox.com/pygments.html +pygmentsStyle = "tango" + +# Configure how URLs look like per section. +[permalinks] +blog = "/:section/:year/:month/:day/:slug/" + + +## Configuration for BlackFriday markdown parser: https://github.com/russross/blackfriday +[blackfriday] +plainIDAnchors = true +hrefTargetBlank = true +angledQuotes = false +latexDashes = true + +# Image processing configuration. +[imaging] +resampleFilter = "CatmullRom" +quality = 75 +anchor = "smart" + +[services] +[services.googleAnalytics] +# Comment out the next line to disable GA tracking. Also disables the feature described in [params.ui.feedback]. +#id = "UA-00000000-0" + +# Language configuration + +[languages] +[languages.en] +title = "Behavior Graph" +description = "Behaior Graph Documentation" +languageName ="English" +# Weight used for sorting. +weight = 1 +#[languages.no] +#title = "Goldydocs" +#description = "Docsy er operativsystem for skyen" +#languageName ="Norsk" +#contentDir = "content/no" +#time_format_default = "02.01.2006" +#time_format_blog = "02.01.2006" + +#[languages.fa] +#title = "اسناد گلدی" +#description = "یک نمونه برای پوسته داکسی" +#languageName ="فارسی" +#contentDir = "content/fa" +#time_format_default = "2006.01.02" +#time_format_blog = "2006.01.02" + +[markup] + [markup.goldmark] + [markup.goldmark.renderer] + unsafe = true + [markup.highlight] + # See a complete list of available styles at https://xyproto.github.io/splash/docs/all.html + style = "tango" + # Uncomment if you want your chosen highlight style used for code blocks without a specified language + guessSyntax = "false" + +# Everything below this are Site Params + +[security] + [security.exec] + allow = ['^dart-sass-embedded$', '^go$', '^npx$', '^postcss$', '^asciidoctor$'] + +# Comment out if you don't want the "print entire section" link enabled. +[outputs] +section = ["HTML", "print", "RSS"] + +[params] +copyright = "Yahoo" +#privacy_policy = "https://policies.google.com/privacy" + +# First one is picked as the Twitter card image if not set on page. +# images = ["images/project-illustration.png"] + +# Menu title if your navbar has a versions selector to access old versions of your site. +# This menu appears only if you have at least one [params.versions] set. +version_menu = "Releases" + +# Flag used in the "version-banner" partial to decide whether to display a +# banner on every page indicating that this is an archived version of the docs. +# Set this flag to "true" if you want to display the banner. +archived_version = false + +# The version number for the version of the docs represented in this doc set. +# Used in the "version-banner" partial to display a version number for the +# current doc set. +version = "1.0.0" + +# A link to latest version of the docs. Used in the "version-banner" partial to +# point people to the main doc site. +url_latest_version = "https://yahoo.github.io/bgdocs" + +# Repository configuration (URLs for in-page links to opening issues and suggesting changes) +#github_repo = "https://github.com/google/docsy-example" +# An optional link to a related project repo. For example, the sibling repository where your product code lives. +#github_project_repo = "https://github.com/google/docsy" + +# Specify a value here if your content directory is not in your repo's root directory +# github_subdir = "" + +# Uncomment this if you have a newer GitHub repo with "main" as the default branch, +# or specify a new value if you want to reference another branch in your GitHub links +# github_branch= "main" + +# Google Custom Search Engine ID. Remove or comment out to disable search. +#gcs_engine_id = "d72aa9b2712488cc3" + +# Enable Algolia DocSearch +algolia_docsearch = false + +# Enable Lunr.js offline search +offlineSearch = false + +# Enable syntax highlighting and copy buttons on code blocks with Prism +prism_syntax_highlighting = false + +# User interface configuration +[params.ui] +# Set to true to disable breadcrumb navigation. +breadcrumb_disable = false +# Set to true to disable the About link in the site footer +footer_about_disable = false +# Set to false if you don't want to display a logo (/assets/icons/logo.svg) in the top navbar +navbar_logo = true +# Set to true if you don't want the top navbar to be translucent when over a `block/cover`, like on the homepage. +navbar_translucent_over_cover_disable = false +# Enable to show the side bar menu in its compact state. +sidebar_menu_compact = false +# Set to true to hide the sidebar search box (the top nav search box will still be displayed if search is enabled) +sidebar_search_disable = false + +# Adds a H2 section titled "Feedback" to the bottom of each doc. The responses are sent to Google Analytics as events. +# This feature depends on [services.googleAnalytics] and will be disabled if "services.googleAnalytics.id" is not set. +# If you want this feature, but occasionally need to remove the "Feedback" section from a single page, +# add "hide_feedback: true" to the page's front matter. +[params.ui.feedback] +enable = false +# The responses that the user sees after clicking "yes" (the page was helpful) or "no" (the page was not helpful). +#yes = 'Glad to hear it! Please tell us how we can improve.' +#no = 'Sorry to hear that. Please tell us how we can improve.' + +# Adds a reading time to the top of each doc. +# If you want this feature, but occasionally need to remove the Reading time from a single page, +# add "hide_readingtime: true" to the page's front matter +[params.ui.readingtime] +enable = false + +[params.links] +# End user relevant links. These will show up on left side of footer and in the community page if you have one. +#[[params.links.user]] + #name = "User mailing list" + #url = "https://example.org/mail" + #icon = "fa fa-envelope" + #desc = "Discussion and help from your fellow users" +#[[params.links.user]] + #name ="Twitter" + #url = "https://example.org/twitter" + #icon = "fab fa-twitter" + #desc = "Follow us on Twitter to get the latest news!" +#[[params.links.user]] + #name = "Stack Overflow" + #url = "https://example.org/stack" + #icon = "fab fa-stack-overflow" + #desc = "Practical questions and curated answers" +# Developer relevant links. These will show up on right side of footer and in the community page if you have one. +#[[params.links.developer]] + #name = "GitHub" + #url = "https://github.com/google/docsy" + #icon = "fab fa-github" + #desc = "Development takes place here!" +#[[params.links.developer]] + #name = "Slack" + #url = "https://example.org/slack" + #icon = "fab fa-slack" + #desc = "Chat with other project developers" +#[[params.links.developer]] + #name = "Developer mailing list" + #url = "https://example.org/mail" + #icon = "fa fa-envelope" + #desc = "Discuss development issues around the project" + +[params.mermaid] + enable = true + diff --git a/doc-site/content/en/_index.md b/doc-site/content/en/_index.md new file mode 100644 index 0000000..5d810ba --- /dev/null +++ b/doc-site/content/en/_index.md @@ -0,0 +1,89 @@ +--- +title: "Behavior Graph" +linkTitle: "Documentation" +weight: 20 +type: "docs" + +cascade: +- type: "blog" + # set to false to include a blog section in the section nav along with docs + toc_root: true + _target: + path: "/blog/**" +- type: "docs" + _target: + path: "/**" + kind: "page" +- type: "docs" + _target: + path: "/**" + kind: "section" +--- + +Behavior Graph is a software architecture and state management library. It greatly enhances your ability to write complex user facing software and control systems. Broadly speaking, it belongs to the category of libraries which includes Redux, MobX, Rx (Reactive Extensions), and XState. It works by providing a specialized unit of composition which we call the __behavior__. Behaviors are simple blocks of code together with their dependency relationships. + +## Is it any good? + +Yes + +## Highlights + +* Minimal boilerplate +* Scales from the simple to the very complex +* Incremental adoption: works alongside existing code and frameworks +* Handles state, events, and effects all in one +* Multi-platform (Javascript/Typescript, Kotlin, Objective-C, Swift) + +We developed Behavior Graph to address our own complexity challenges while building an iOS video playing library which is used internally throughout the suite of native Yahoo mobile apps. After years of development and production usage, it has proven to be incredibly competent at scale. We have since ported it to multiple languages including Javascript/Typescript. It is less than 1500 lines of code and contains no external dependencies. + +Behavior Graph will particularly appeal to anyone with a willingness to rethink how we write software applications. + +## What does it look like? + +The below block of code implements a simple counter using Behavior Graph. +It can increment the counter or reset it back to zero. + +About 70% of the concepts you need to work with Behavior Graph are contained in this one example. + + +{{< highlight javascript >}} +this.increment = this.moment(); +this.reset = this.moment(); +this.counter = this.state(0); + +this.behavior() + .demands(this.increment, this.reset) + .supplies(this.counter) + .runs(this => { + if (this.increment.justUpdated) { + this.counter.update(this.counter.value + 1); + } else if (this.reset.justUpdated) { + this.counter.update(0); + } + }); +{{< /highlight >}} + +A typical Behavior Graph program consists of dozens or hundreds of behaviors like this, each with its own responsibilities. +The Behavior Graph library then ensures these behaviors are correctly specified and runs them at the correct time and in the correct order. +At scale this is shockingly effective. + +## Is it for me? + +Behavior Graph is a general purpose library which you can use to organize the event driven logic in any program. +It should also be of interest to anyone with an interest in software engineering and architectures. + +Specifically if you are working on any of these categories, you should definitely consider it: + +* Web apps +* Mobile apps +* Desktop Applications +* User Interfaces +* Control Systems +* Robots +* Games + +## Learning Behavior Graph + +While there are only a handful of basic concepts in Behavior Graph, it does require a shift in thinking. +We recommend you start with the [Quick Start]({{< ref quickstart >}}) then work through the [Tutorials]({{< ref "tutorials/tutorial-1" >}}). +They will help you understand how the pieces fit together. diff --git a/doc-site/content/en/api.md b/doc-site/content/en/api.md new file mode 100644 index 0000000..e836bf4 --- /dev/null +++ b/doc-site/content/en/api.md @@ -0,0 +1,599 @@ +--- +title: "API" +weight: 40 +--- +# Types + +## Behavior + +A behavior is a block of code together with its dependency relationships (links). +They are one of the two node types in a behavior graph. +You define behaviors using the `behavior()` factory method of an Extent. + +Behaviors have both static and dynamic links. +You provide static links when you create the behavior. +Behavior Graph will update dynamic links per special methods on BehaviorBuilder or you can update them directly on a behavior. + +### `demands` + +* returns: `Set | null` +* _read only property_ + +The current set of all Resources which the behavior demands. + +### `extent` + +* returns: `Extent` +* _read only property_ + +A behavior always has an Extent with which it is created. + +### `setDynamicDemands()` + +* param: `newDemands: (Demandable | undefined)[] | null)` + +Provide an array of Demandables. +`undefined` is also an element type to make for easier use of optional chaining. +Providing `null` is equivalent to saying there are no dynamic demands. + +### `setDynamicSupplies()` + +* param: `newSupplies: (Resource | undefined)[] | null)` + +Provide an array of Resources to supply. +`undefined` is also an element type to make for easier use of optional chaining. +Providing `null` is equivalent to saying there are no dynamic supplies. + +### `supplies` + +* returns: `Set | null` +* _read only property_ + +The current set of all Resources which the behavior supplies. + + +## BehaviorBuilder + +BehaviorBuilder provides fluent API for constructing instances of a Behavior. +You create an instance of a BehaviorBuilder using the `behavior()` method on Extent. +All methods except `runs()` return the same instance of BehaviorBuilder so you can chain multiple optional clauses. + +Generic type T is the Extent subtype BehaviorBuilder is created with. + + +{{< highlight javascript >}} +// Create a single behavior with one demand and one supply. +this.moment1 = this.moment(); +this.moment2 = this.moment(); +this.moment3 = this.moment(); +this.behavior() + .demands(this.moment1, this.moment2) + .supplies(this.moment3) + .runs(ext => { + if (ext.moment1.justUpdated || ext.moment2.justUpdatedTo(false)) { + ext.moment3.update(); + } + }); +{{< /highlight >}} + +### `demands()` + +* params: `...demands: Demandable[]` +* returns: `BehaviorBuilder` + +Provide a list of static demands this behavior will link to. + +### `dynamicDemands()` + +* param: `switches: Demandable[]` +* param: `links: ((ext: T) => (Demandable | undefined)[] | null)` +* param: `relinkingOrder?: RelinkingOrder` +* returns: `BehaviorBuilder` + +This clause updates the dynamicDemands of this behavior based on the updating of other resources, the switches. +When the switches update, the links parameter will be called which should return the list of new resources. + +We permit `undefined` in the list to make for easier optional chaining. +Returning `null` is equivalent to setting no dynamicDemands. + +`relinkingOrder` parameter can optionally be set to `Extent.relinkingOrderSubsequent` which will update the demands _after_ the runs block is run. + + +{{< highlight javascript >}} +// This behavior will automatically demand the deleteButton resource of +// the currentChild extent whenever it changes. +this.currentChild = this.state(null); +this.behavior() + .dynamicDemands([this.currentChild], ext => { + return [ext.currentChild.value?.deleteButton]; + }) + .runs(ext => { + if (ext.currentChild.value?.deleteButton.justUpdated) { + // do something in response + } + }); +{{< /highlight >}} + +### `dynamicSupplies()` + +* param: `switches: Demandable[]` +* param: `links: ((ext: T) => (Resource | undefined)[] | null)` +* returns: `BehaviorBuilder` + +This clause updates the dynamicSupplies similarly to the dynamicDemands clause. + +### `runs()` + +* param: `block: (ext: T) => void` +* returns: `Behavior` + +This clause sets the block of code which will run when the behavior is activated. +The parameter `ext` will be the instance of the Extent this behavior was created on. + +`runs()` will return the created behavior which will typically be ignored. + +### `supplies()` + +* params: `...supplies: Resource[]` +* returns: `BehaviorBuilder` + +Provide a list of static supplies this behavior will link to. + +## Extent + +Extents are collections of resources and behaviors. +You will create your own Extent subclasses to define your Behavior Graph functionality. + + +{{< highlight javascript >}} +// Define extent that toggles state on a switch +class MyExtent extends Extent { + constructor(graph) { + super(graph); + + this.toggleSwitch = this.moment(); + this.currentState = this.state(false); + + this.behavior() + .demands(this.toggleSwitch) + .supplies(this.currentState) + .runs(ext => { + this.currentState.update(!this.currentState.value); + }); + } +} + +// Create instance of MyExtent and add it to the graph +let myGraph = new Graph(); +let main = new MyExtent(myGraph); +main.addToGraphWithAction(); +{{< /highlight >}} + +### `action()` + +* param `action: (ext: this) => void` +* param `debugName?: string` + +Calls the `action()` method on the underlying Graph object. +Contains an additional `ext` parameter which will be this Extent instance. + +### `async actionAsync()` + +* param `action: (ext: this) => void` +* param `debugName?: string` +* returns: `Promise` + +Calls the `actionAsync()` method on the underlying Graph object. +Contains an additional `ext` parameter which will be this Extent instance. + +### `addChildLifetime()` + +* param: `extent: Extent` + +Adds the parameter to list of child lifetimes. +An extent with child lifetimes is guaranteed to be part of the graph while the child is. +Behaviors in child extents are permitted to have static links to resources in the parent. + +### `addedToGraph` + +* returns `State` +* _read only_ property + +Every extent comes with this state resource. +It updates to `true` when the extent is added to the graph. + +### `addedToGraphWhen` + +* returns `number | null` +* _read only_ property + +The sequence number of the event the Extent was added to the Graph. +It is null if it has not been added or once it is removed. + +### `addToGraph()` + +Adds this extent to the graph. +Behavior Graph will only interact with resources and behaviors after their extent has been added. + +### `addToGraphWithAction()` + +* param: `debugName?: string` + +Syntactic sugar for creating a new action and calling `addToGraph()`. +`debugName` is passed to the action. + +### `behavior()` + +Creates a BehaviorBuilder instance. + +### `debugName` + +* returns `string | null` +* _read write_ property + +You can define a runtime debugName for your instances to aid in debugging. +It defaults to the name of your Extent subclass. + +### `new Extent()` + +* param: `graph: Graph` +* constructor + +An Extent must be initialized with a Graph. +You must call super() with the graph in your overridden constructor. + +### `graph` + +* returns `Graph` +* _read only_ property + +The graph on which this extent was created. + +### `moment()` + +* param `debugName?: string` + +Factory method to create a moment resource. +By default the `debugName` will be the name of the property that points to this resource. + +### `removeFromGraph()` + +* param `strategy?: ExtentRemoveStrategy` + +After an extent is removed from the graph its resource and behaviors will no longer interact with other extents in the graph. + +Extents must be removed in a manner that is consistent with their lifetimes. +* All extents with a unified lifetime must be removed during the same event. +* All extents that have a parent lifetime must not remain in the graph longer than their parent. + +Providing `Extent.removeContainedLifetimes` as the strategy parameter will automatically remove all extents with the unified or child lifetimes. + +### `removeFromGraphWithAction()` + +* param: `strategy?: ExtentRemoveStrategy` +* param: `debugName?: string` + +Syntactic sugar for creating a new action and calling `removeFromGraph()`. +`debugName` is passed to the action. + +### `resource()` + +* param `debugName?: string` + +Factory method to create a resource. +By default the `debugName` will be the name of the property that points to this resource. + +### `sideEffect()` + +* param `block: (ext: this) => void` +* param `debugName?: string` + +Calls the `sideEffect()` method on the underlying Graph object. +Contains an additional `ext` parameter + +### `state()` + +* param `initialState: T` +* param `debugName?: string` + +Factory method to create a state resource. +By default the `debugName` will be the name of the property that points to this resource. + +### `unifyLifetime()` + +* param: `extent: Extent` + +Combines the lifetime of this extent with that of the parameter. +Extents with unified lifetimes are guaranteed to be part of the graph for the same period of time. +They are permitted to have static links between them. + +## Graph + +### `action()` + +* param `block: () => void` +* param `debugName?: string` + +Creates a synchronous action on the graph. +By default the debugName will be derived from the set of resources that are updated inside the action block. + +### `async actionAsync()` + +* param `block: () => void` +* param `debugName?: string` +* returns: `Promise` + +Creates an action that will run asynchronously. + +### `currentBehavior` + +* returns `Behavior | null` +* _read only_ property + +Returns the currently running behavior or null if otherwise. + +### `currentEvent` + +* returns `GraphEvent | null` +* _read only_ property + +Returns the current GraphEvent if the graph is running an event or null otherwise. + +### `dateProvider` + +* returns: `GraphDateProvider` +* _read write_ property + +The default dateProvider returns `Date.now()` which is the source of `timestamp` on GraphEvent instances. +Overriding is primarily useful for controlling values during testing. + +### `debugCycleForBehavior()` + +* param `behavior: Behavior` +* returns: `Resource[]` + +Used during debugging as an aid when there are dependency cycles. +The returned array contains the sequence of Resource objects which will result in a dependency cycle including this behavior. +The array will be empty if there is not a cycle. + +### `lastEvent` + +* returns `GraphEvent` +* _read only_ property + +Returns the last GraphEvent that completed. +It starts as `GraphEvent.initialEvent`. + +### `sideEffect()` + +* param: `block: () => void` +* param: `debugName?: string` + +Creates a block of code that will run during the side effect phase of the event. + +## GraphEvent + +### `sequence` + +* returns: `number` +* _read only_ property + +Each GraphEvent is assigned a monotonically increasing number for each event run on the graph. +You can use this information to quickly determine the order resources update. + +### `timestamp` + +* returns: `Date` +* _read only_ property + +Each GraphEvent is given a timestamp according to the registered DateProvider given to a graph instance. +It defaults to `Date.now()`. + +## Moment + +_extends Resource_ + +A Moment is a type of Resource for tracking information that exists at a moment in time. +Button presses or network call returns are examples of Moments. + +Moments optionally have values associated with them. +The payload of a network call return is a possible value for a moment. +Those values are reset to `undefined` at the end of the event. + +### `event` + +* returns `GraphEvent | null` +* _read only_ property + +Returns the GraphEvent of the most recent time the moment was updated. +It is `null` if it has never been updated. + +### `justUpdated` + +* returns: `boolean` +* _read only_ property + +Returns true if the moment updated during this event. + +### `justUpdatedTo()` + +* param `value: T` +* returns `boolean` + +Returns true if the moment was justUpdated and the value `==` the parameter. +If you wish to use something different than `==` you can implement your own check as this method is syntactic sugar. + +### `update()` + +* param `value: T | undefined` + +Marks the moment as justUpdated. +If a value is provided, it will be set on the moment for reading. + +### `updateWithAction()` + +* param `value: T | undefined` +* param `debugName? : string` + +Syntactic sugar for calling `action()` on the underlying graph and calling `update()` on the moment. + +### `value` + +* returns `T` +* _read only_ property + +Returns the value stored in the moment if it was updated during this event. +It is `undefined` if it was not updated or outside of an event. + +Moments do not necessarily have a value. +They will not if they were not given one in their `update()` method. + +## Resource + +The base class for State and Moment. +Prefer those types in almost all circumstances. +Wherever you see "resource" in this document, assume we are referring to instances of State and Moment. + +Resource has minimal functionality. +Using instances of this base class directly is useful when forcing a certain ordering relationship between behaviors. + +### `debugName` + +* returns `string | null` +* _read write_ property + +Assignable name for use during debugging. + +### `extent` + +* returns `Extent` +* _read only_ property + +All resources belong to an Extent. + +### `graph` + +* returns `Graph` +* _read only_ property + +All resources belong to a Graph. + +### `order` + +* returns `Demandable` +* _read only_ property + +A behavior can also demand `resource.order` which tells the behavior not to activate when the resource updates. + +### `suppliedBy` + +* returns `Behavior | null` +* _read only_ property + +If the resource is supplied by a behavior it will be returned, null otherwise. + +## State + +_extends Resource_ + +A State is a type of resource for storing information over a period of time. +Its value will persist into the future until it is updated. + +All States must be given an initial value when created. + +### `event` + +* returns `GraphEvent` +* _read only_ property + +The last time the State was updated. +Will return `GraphEvent.initialEvent` for its initial value before it has been updated. + +### `justUpdated` + +* returns `boolean` +* _read only_ property + +Returns true if the state was updated during this event. + +### `justUpdatedTo()` + +* param: `toState: T` +* returns: `boolean` + +Returns true if the state was updated during this event and toState parameter `==` value. + +### `justUpdatedFrom()` + +* param: `fromState: T` +* returns: `boolean` + +Returns true if the state was updated during this event and the fromState parameter `==` the value it had before updating. + +### `justUpdatedToFrom()` + +* param: `toState: T` +* param: `fromState: T` +* returns: `boolean` + +A combination of `justUpdatedTo()` and `justUpdatedFrom()` + +### `traceEvent` + +* returns: `GraphEvent` +* _read only_ property + +What was the value of the `event` property at the beginning of the current event. + +### `traceValue` + +* returns: `T` +* _read only_ property + +What was the value of the `value` property at the beginning of the current event. + +### `updateWithAction()` + +* param: `newValue: T` +* param: `debugName?: string` + +Equivalent to calling `action()` on the underlying Graph instance and `update()` on the State object. + +### `update()` + +* param: `newValue: T` + +Checks to see if the newValue parameter `!==` the current value, and if so updates it to that new value. + +### `updateForce()` + +* param: `newValue: T` + +Updates value to the newValue even if they are the same. + +### `value` + +* returns: `T` +* _read only_ property + +The current underlying value. + +# Interfaces + +## Demandable + +What a behavior can demand. A sealed opaque type which includes: +* Instances of Resource and its subclasses State and Moment +* The object returned by `.order` on an instance of Resource + +There are no other Demandable types and it is not open for extension. + +## DateProvider + +Optional override for default `dateProvier` on Graph instance. + +Implement a type with a single method: + +`now(): Date` + + diff --git a/doc-site/content/en/api.md.bak b/doc-site/content/en/api.md.bak new file mode 100644 index 0000000..a804a31 --- /dev/null +++ b/doc-site/content/en/api.md.bak @@ -0,0 +1,588 @@ +--- +title: "API" +--- +# Types + +## Behavior + +A behavior is a block of code together with its dependency relationships (links). +They are one of the two node types in a behavior graph. +You define behaviors using the `behavior()` factory method of an Extent. + +Behaviors have both static and dynamic links. +You provide static links when you create the behavior. +Behavior Graph will update dynamic links per special methods on BehaviorBuilder or you can update them directly on a behavior. + +### `demands` + +* returns: `Set | null` +* _read only property_ + +The current set of all Resoruces which the behavior demands. + +### `extent` + +* returns: `Extent` +* _read only property_ + +A behavior always has an Extent with which it is created. + +### `setDynamicDemands()` + +* param: `newDemands: (Demandable | undefined)[] | null)` + +Provide an array of Demandables. +`undefined` is also an element type to make for easier use of optional chaining. +Providing `null` is equivalent to saying there are no dynamic demands. + +### `setDynamicSupplies()` + +* param: `newSupplies: (Resource | undefined)[] | null)` + +Provide an array of Resources to supply. +`undefined` is also an element type to make for easier use of optional chaining. +Providing `null` is equivalent to saying there are no dynamic supplies. + +### `supplies` + +* returns: `Set | null` +* _read only property_ + +The current set of all Resources which the behavior supplies. + + +## BehaviorBuilder + +BehaviorBuilder provides fluent API for constructing instances of a Behavior. +You create an instance of a BehaviorBuilder using the `behavior()` method on Extent. +All methods except `runs()` return the same instance of BehaviorBuilder so you can chain multiple optional clauses. + +Generic type T is the Extent subtype BehaviorBuilder is created with. + + +{{< highlight javascript >}} +// Create a single behavior with one demand and one supply. +this.moment1 = this.moment(); +this.moment2 = this.moment(); +this.moment3 = this.moment(); +this.behavior() + .demands(this.moment1, this.moment2) + .supplies(this.moment3) + .runs(ext => { + if (ext.moment1.justUpdated || ext.moment2.justUpdatedTo(false)) { + ext.moment3.update(); + } + }); +{{< /highlight >}} + +### `demands()` + +* params: `...demands: Demandable[]` +* returns: `BehaviorBuilder` + +Provide a list of static demands this behavior will link to. + +### `dynamicDemands()` + +* param: `switches: Demandable[]` +* param: `links: ((ext: T) => (Demandable | undefined)[] | null)` +* param: `relinkingOrder?: RelinkingOrder` +* returns: `BehaviorBuilder` + +This clause updates the dynamicDemands of this behavior based on the updating of other resources, the switches. +When the switches update, the links parameter will be called which should return the list of new resources. + +We permit `undefined` in the list to make for easier optional chaning. +Returning `null` is equivalent to setting no dynamicDemands. + +`relinkingOrder` parameter can optionally be set to `Extent.relinkingOrderSubsequent` which will update the demands _after_ the runs block is run. + + +{{< highlight javascript >}} +// This behavior will automatically demand the deleteButton resource of +// the currentChild extent whenever it changes. +this.currentChild = this.state(null); +this.behavior() + .dynamicDemands([this.currentChild], ext => { + return [ext.currentChild.value?.deleteButton]; + }) + .runs(ext => { + if (ext.currentChild.value?.deleteButton.justUpdated) { + // do something in response + } + }); +{{< /highlight >}} + +### `dynamicSupplies()` + +* param: `switches: Demandable[]` +* param: `links: ((ext: T) => (Resource | undefined)[] | null)` +* returns: `BehaviorBuilder` + +This clause updates the dynamicSupplies similarly to the dynamicDemands clause. + +### `runs()` + +* param: `block: (ext: T) => void` +* returns: `Behavior` + +This clause sets the block of code which will run when the behavior is activated. +The parameter `ext` will be the instance of the Extent this behavior was created on. + +`runs()` will return the created behavior which will typically be ignored. + +### `supplies()` + +* params: `...supplies: Resource[]` +* returns: `BehaviorBuilder` + +Provide a list of static supplies this behavior will link to. + +## Extent + +Extents are collections of resources and behaviors. +You will create your own Extent subclasses to define your Behavior Graph functionality. + +{{< highlight javascript >}} +// Define extent that toggles state on a switch +class MyExtent extends Extent { + constructor(graph) { + super(graph); + + this.toggleSwitch = this.moment(); + this.onState = this.state(false); + + this.behavior() + .demands(this.toggleSwitch) + .supplies(this.onState) + .runs(ext => { + this.onState.update(!this.onState.value); + }); + } +} + +// Create instance of MyExtent and add it to the graph +let myGraph = new Graph(); +let main = new MyExtent(myGraph); +main.addToGraphWithAction(); +{{< /highlight >}} + +### `action()` + +* param `action: (ext: this) => void` +* param `debugName?: string` + +Calls the `action()` method on the underlying Graph object. +Contains an additional `ext` parameter. + +### `async actionAsync()` + +* param `action: (ext: this) => void` +* param `debugName?: string` +* returns: `Promise` + +Calls the `actionAsync()` method on the underlying Graph object. +Contains an additional `ext` parameter. + +### `addChildLifetime()` + +* param: `extent: Extent` + +Adds the parameter to list of child lifetimes. +An extent extents with child lifetimes is guarantee to be part of the graph while the child is. +Behaviors in Child extents are permitted to have static links to resources in the parent. + +### `addedToGraph` + +* returns `State` +* _read only_ property + +Every extent comes with this state resource. +It updates to `true` when the extent is added to the graph. + +### `addedToGraphWhen` + +* returns `number | null` +* _read only_ proptery + +### `addToGraph()` + +Adds this extent to the graph. +Behavior Graph will only interact with resoruces and behaviors after their extent has been added. + +### `addToGraphWithAction()` + +* param: `debugName?: string` + +Syntactic sugar for creating a new action and calling `addToGraph()`. +`debugName` is passed to the action. + +### `behavior()` + +Creates a BehaviorBuilder instance. + +### `debugName` + +* returns `string | null` +* _read write_ property + +You can define a runtime debugName for your instances to aid in debugging. +It defaults to the name of your Extent subclass. + +### `new Extent()` + +* param: `graph: Graph` +* constructor + +An Extent must be initialized with a Graph. +You must call super() with the graph in your overriden constructor. + +### `graph` + +* returns `Graph` +* _read only_ property + +The graph on which this extent was created. + +### `moment()` + +* param `debugName?: string` + +Factory method to create a moment resource. +By default the `debugName` will be the name of the property that points to this resource. + +### `removeFromGraph()` + +* param `strategy?: ExtentRemoveStrategy` + +After an extent is removed from the graph its resource and behaviors will no longer interact with other extents in the graph. + +Extents must be removed in a manner that is consistent with their lifetimes. +* All extents with a unified lifetime must be removed during the same event. +* All extents that have a parent lifetime must not remain in the graph longer than their parent. + +Providing `Extent.removeContainedLifetimes` as the strategy parameter will automatically remove all extents with the unified or child lifetimes. + +### `removeFromGraphWithAction()` + +* param: `strategy?: ExtentRemoveStrategy` +* param: `debugName?: string` + +Syntactic sugar for creating a new action and calling `removeFromGraph()`. +`debugName` is passed to the action. + +### `resource()` + +* param `debugName?: string` + +Factory method to create a resource. +By default the `debugName` will be the name of the property that points to this resource. + +### `sideEffect()` + +* param `block: (ext: this) => void` +* param `debugName?: string` + +Calls the `sideEffect()` method on the underlying Graph object. +Contains an additional `ext` parameter + +### `state()` + +* param `initialState: T` +* param `debugName?: string` + +Factory method to create a state resource. +By default the `debugName` will be the name of the property that points to this resource. + +### `unifyLifetime()` + +* param: `extent: Extent` + +Combines the lifetime of this Extent instance with that of the parameter. +Extents with unified lifetimes are guaranteed to be part of the graph for the same period of time. +They are permitted to have static links between them. + +## Graph + +### `action()` + +* param `block: () => void` +* param `debugName?: string` + +Creates a synchronous action on the graph. +By default the debugName will be derived from the set of resources that are updated inside the action block. + +### `async actionAsync()` + +* param `block: () => void` +* param `debugName?: string` +* returns: `Promise` + +Creates an action that will run asynchronously. + +### `currentBehavior` + +* returns `Behavior | null` +* _read only_ property + +Returns the currently running behavior or null if otherwise. + +### `currentEvent` + +* returns `GraphEvent | null` +* _read only_ property + +Returns the current GraphEvent if the graph is running an event, null otherwise. + +### `dateProvider` + +* returns: `GraphDateProvider` +* _read write_ property + +The default dateProvider returns `Date.now()` which is the source of `timestamp` on GraphEvent instances. +Overriding is primarily useful for controlling values during testing. + +### `debugCycleForBehavior()` + +* param `behavior: Behavior` +* returns: `Resource[]` + +Used during debugging aid when there are dependency cycles. +The returned array contains the sequence of Resource objects which will result in a dependency cycle including this behavior. +The array will be empty if there is not a cycle. + +### `lastEvent` + +* returns `GraphEvent` +* _read only_ property + +Returns the last GraphEvent that completed. +It starts as `GraphEvent.initialEvent`. + +### `sideEffect()` + +* param: `block: () => void` +* param: `debugName?: string` + +Creates a block of code that will run during the side effect phase of the event. + +## GraphEvent + +### `sequence` + +* returns: `number` +* _read only_ property + +Each GraphEvent is assigned a monotonically increasing number for each event run on the graph. + +### `timestamp` + +* returns: `Date` +* _read only_ property + +Each GraphEvent is given the timestamp according to the registered GraphDateProvider given to a graph instance. +It defaults to `Date.now()`. + +## Moment + +_extends Resource_ + +A Moment is a type of Resource for tracking information that exists at a moment in time. +Button presses or network call returns are examples of Moments. + +Moments optionally have values associated with them. +The payload of a network call return is a possible value for a moment. +Those values are reset to `undefined` at the end of the event. + +### `event` + +* returns `GraphEvent | null` +* _read only_ property +* demanding behavior + +Returns the GraphEvent of the most recent time the moment was updated. +It is `null` if it has never been updated. + +### `justUpdated` + +* returns: `boolean` +* _read only_ property +* demanding behavior + +Returns true if the moment updated during this event. + +### `justUpdatedTo()` + +* param `value: T` +* returns `boolean` + +Returns true if the moment was justUpdated and the value `==` the parameter. +If you wish to use something different than `==` you can implement your own check as this method is syntactic sugar. + +### `update()` + +* param `value: T | undefined` + +Marks the moment as justUpdated. +If a value is provided, it will be set on the moment for reading. + +### `updateWithAction()` + +* param `value: T | undefined` +* param `debugName? : string` + +Synctactic sugar for calling `action()` on the underlying graph and calling `update()` on the moment. + +### `value` + +* returns `T` +* _read only_ property + +Returns the value stored in the moment if it was updated during this event. +It is `undefined` if it was not updated or outside of an event. + +## Resource + +The base class for State and Moment. +Prefer those types for modeling your problems. + +### `debugName` + +* returns `string | null` +* _read write_ property + +Assignable name for use during debugging. + +### `extent` + +* returns `Extent` +* _read only_ property + +All resources belong to an Extent. + +### `graph` + +* returns `Graph` +* _read only_ property + +All resources belong to a Graph. + +### `order` + +* returns `Demandable` +* _read only_ property + +A behavior can also demand `resource.order` which tells the behavior not to activate when the resource updates. + +### `suppliedBy` + +* returns `Behavior | null` +* _read only_ property + +If the resource is supplied by a behavior it will be this return, null otherwise. + +## State + +_extends Resource_ + +A State is a type of resource for storing information over a period of time. +Its value will persist into the future until it is updated. + +All States must be given an initial value when created. + +### `event` + +* returns `GraphEvent` +* _read only_ property + +The last time the State was updated. +Its event property will be `GraphEvent.initialEvent` for its initial value before it is updated. + +### `justUpdated` + +* returns `boolean` +* _read only_ property + +Returns true if the state was updated during this event. + +### `justUpdatedTo()` + +* param: `toState: T` +* returns: `boolean` + +Returns true if the state was updated during this event and toState parameter `==` value. + +### `justUpdatedFrom()` + +* param: `fromState: T` +* returns: `boolean` + +Returns true if the state was updated during this event and the fromState parameter `==` the value it had before updating. + +### `justUpdatedToFrom()` + +* param: `toState: T` +* param: `fromState: T` +* returns: `boolean` + +A combination of `justUpdatedTo()` and `justUpdatedFrom()` + +### `traceEvent` + +* returns: `GraphEvent` +* _read only_ property + +What was the value of the `event` property at the beginning of the current event. + +### `traceValue` + +* returns: `T` +* _read only_ property + +What was the value of the `value` property at the beginning of the current event. + +### `updateWithAction()` + +* param: `newValue: T` +* param: `debugName?: string` + +Equivalent to calling `action()` on the underlying Graph instance and `update()` on the State object. + +### `update()` + +* param: `newValue: T` + +Checks to see if the newValue parameter `!=` the current value, and if so updates it to that new value. + +### `updateForce()` + +* param: `newValue: T` + +Updates value to the newValue even if they are the same. + +### `value` + +* returns: `T` +* _read only_ property + +The current underlying value. + +# Interfaces + +## Demandable + +What a behavior can demand. A sealed opaque type which includes: +* Instances of Resource and its subclasses State and Moment +* The object returned by `.order` on an instance of Resource + +There are no other Demandable types and it is not open for extension. + +## GraphDateProvider + +Optional override for default `dateProvier` on Graph instance. + +Implement a type with a single method: + +`now(): Date` + + diff --git a/doc-site/content/en/blog/_index.md b/doc-site/content/en/blog/_index.md new file mode 100644 index 0000000..43820eb --- /dev/null +++ b/doc-site/content/en/blog/_index.md @@ -0,0 +1,13 @@ +--- +title: "Docsy Blog" +linkTitle: "Blog" +menu: + main: + weight: 30 +--- + + +This is the **blog** section. It has two categories: News and Releases. + +Files in these directories will be listed in reverse chronological order. + diff --git a/doc-site/content/en/blog/news/_index.md b/doc-site/content/en/blog/news/_index.md new file mode 100644 index 0000000..13d25ea --- /dev/null +++ b/doc-site/content/en/blog/news/_index.md @@ -0,0 +1,8 @@ + +--- +title: "News About Docsy" +linkTitle: "News" +weight: 20 +--- + + diff --git a/doc-site/content/en/blog/news/first-post/featured-sunset-get.png b/doc-site/content/en/blog/news/first-post/featured-sunset-get.png new file mode 100644 index 0000000..db3373c Binary files /dev/null and b/doc-site/content/en/blog/news/first-post/featured-sunset-get.png differ diff --git a/doc-site/content/en/blog/news/first-post/index.md b/doc-site/content/en/blog/news/first-post/index.md new file mode 100644 index 0000000..b6bfb47 --- /dev/null +++ b/doc-site/content/en/blog/news/first-post/index.md @@ -0,0 +1,46 @@ +--- +date: 2018-10-06 +title: "Easy documentation with Docsy" +linkTitle: "Announcing Docsy" +description: "The Docsy Hugo theme lets project maintainers and contributors focus on content, not on reinventing a website infrastructure from scratch" +author: Riona MacNamara ([@rionam](https://twitter.com/bepsays)) +resources: +- src: "**.{png,jpg}" + title: "Image #:counter" + params: + byline: "Photo: Riona MacNamara / CC-BY-CA" +--- + +**This is a typical blog post that includes images.** + +The front matter specifies the date of the blog post, its title, a short description that will be displayed on the blog landing page, and its author. + +## Including images + +Here's an image (`featured-sunset-get.png`) that includes a byline and a caption. + +{{< imgproc sunset Fill "600x300" >}} +Fetch and scale an image in the upcoming Hugo 0.43. +{{< /imgproc >}} + +The front matter of this post specifies properties to be assigned to all image resources: + +``` +resources: +- src: "**.{png,jpg}" + title: "Image #:counter" + params: + byline: "Photo: Riona MacNamara / CC-BY-CA" +``` + +To include the image in a page, specify its details like this: + +``` +{{< imgproc sunset Fill "600x300" >}} +Fetch and scale an image in the upcoming Hugo 0.43. +{{< /imgproc >}} +``` + +The image will be rendered at the size and byline specified in the front matter. + + diff --git a/doc-site/content/en/blog/news/second-post.md b/doc-site/content/en/blog/news/second-post.md new file mode 100755 index 0000000..0ef58d7 --- /dev/null +++ b/doc-site/content/en/blog/news/second-post.md @@ -0,0 +1,245 @@ + +--- +title: "The second blog post" +linkTitle: "Second blog post" +date: 2018-10-06 +description: > + A short lead description about this content page. Text here can also be **bold** or _italic_ and can even be split over multiple paragraphs. +--- + +Text can be **bold**, _italic_, or ~~strikethrough~~. [Links](https://github.com) should be blue with no underlines (unless hovered over). + +There should be whitespace between paragraphs. There should be whitespace between paragraphs. There should be whitespace between paragraphs. There should be whitespace between paragraphs. + +There should be whitespace between paragraphs. There should be whitespace between paragraphs. There should be whitespace between paragraphs. There should be whitespace between paragraphs. + +> There should be no margin above this first sentence. +> +> Blockquotes should be a lighter gray with a border along the left side in the secondary color. +> +> There should be no margin below this final sentence. + +## First Header + +This is a normal paragraph following a header. Bacon ipsum dolor sit amet t-bone doner shank drumstick, pork belly porchetta chuck sausage brisket ham hock rump pig. Chuck kielbasa leberkas, pork bresaola ham hock filet mignon cow shoulder short ribs biltong. Bacon ipsum dolor sit amet t-bone doner shank drumstick, pork belly porchetta chuck sausage brisket ham hock rump pig. Chuck kielbasa leberkas, pork bresaola ham hock filet mignon cow shoulder short ribs biltong. Bacon ipsum dolor sit amet t-bone doner shank drumstick, pork belly porchetta chuck sausage brisket ham hock rump pig. Chuck kielbasa leberkas, pork bresaola ham hock filet mignon cow shoulder short ribs biltong. + + + +Bacon ipsum dolor sit amet t-bone doner shank drumstick, pork belly porchetta chuck sausage brisket ham hock rump pig. Chuck kielbasa leberkas, pork bresaola ham hock filet mignon cow shoulder short ribs biltong. + +On big screens, paragraphs and headings should not take up the full container width, but we want tables, code blocks and similar to take the full width. + +Lorem markdownum tuta hospes stabat; idem saxum facit quaterque repetito +occumbere, oves novem gestit haerebat frena; qui. Respicit recurvam erat: +pignora hinc reppulit nos **aut**, aptos, ipsa. + +Meae optatos *passa est* Epiros utiliter *Talibus niveis*, hoc lata, edidit. +Dixi ad aestum. + +## Header 2 + +> This is a blockquote following a header. Bacon ipsum dolor sit amet t-bone doner shank drumstick, pork belly porchetta chuck sausage brisket ham hock rump pig. Chuck kielbasa leberkas, pork bresaola ham hock filet mignon cow shoulder short ribs biltong. + +### Header 3 + +``` +This is a code block following a header. +``` + +#### Header 4 + +* This is an unordered list following a header. +* This is an unordered list following a header. +* This is an unordered list following a header. + +##### Header 5 + +1. This is an ordered list following a header. +2. This is an ordered list following a header. +3. This is an ordered list following a header. + +###### Header 6 + +| What | Follows | +|-----------|-----------------| +| A table | A header | +| A table | A header | +| A table | A header | + +---------------- + +There's a horizontal rule above and below this. + +---------------- + +Here is an unordered list: + +* Salt-n-Pepa +* Bel Biv DeVoe +* Kid 'N Play + +And an ordered list: + +1. Michael Jackson +2. Michael Bolton +3. Michael Bublé + +And an unordered task list: + +- [x] Create a sample markdown document +- [x] Add task lists to it +- [ ] Take a vacation + +And a "mixed" task list: + +- [ ] Steal underpants +- ? +- [ ] Profit! + +And a nested list: + +* Jackson 5 + * Michael + * Tito + * Jackie + * Marlon + * Jermaine +* TMNT + * Leonardo + * Michelangelo + * Donatello + * Raphael + +Definition lists can be used with Markdown syntax. Definition terms are bold. + +Name +: Godzilla + +Born +: 1952 + +Birthplace +: Japan + +Color +: Green + + +---------------- + +Tables should have bold headings and alternating shaded rows. + +| Artist | Album | Year | +|-------------------|-----------------|------| +| Michael Jackson | Thriller | 1982 | +| Prince | Purple Rain | 1984 | +| Beastie Boys | License to Ill | 1986 | + +If a table is too wide, it should scroll horizontally. + +| Artist | Album | Year | Label | Awards | Songs | +|-------------------|-----------------|------|-------------|----------|-----------| +| Michael Jackson | Thriller | 1982 | Epic Records | Grammy Award for Album of the Year, American Music Award for Favorite Pop/Rock Album, American Music Award for Favorite Soul/R&B Album, Brit Award for Best Selling Album, Grammy Award for Best Engineered Album, Non-Classical | Wanna Be Startin' Somethin', Baby Be Mine, The Girl Is Mine, Thriller, Beat It, Billie Jean, Human Nature, P.Y.T. (Pretty Young Thing), The Lady in My Life | +| Prince | Purple Rain | 1984 | Warner Brothers Records | Grammy Award for Best Score Soundtrack for Visual Media, American Music Award for Favorite Pop/Rock Album, American Music Award for Favorite Soul/R&B Album, Brit Award for Best Soundtrack/Cast Recording, Grammy Award for Best Rock Performance by a Duo or Group with Vocal | Let's Go Crazy, Take Me With U, The Beautiful Ones, Computer Blue, Darling Nikki, When Doves Cry, I Would Die 4 U, Baby I'm a Star, Purple Rain | +| Beastie Boys | License to Ill | 1986 | Mercury Records | noawardsbutthistablecelliswide | Rhymin & Stealin, The New Style, She's Crafty, Posse in Effect, Slow Ride, Girls, (You Gotta) Fight for Your Right, No Sleep Till Brooklyn, Paul Revere, Hold It Now, Hit It, Brass Monkey, Slow and Low, Time to Get Ill | + +---------------- + +Code snippets like `var foo = "bar";` can be shown inline. + +Also, `this should vertically align` ~~`with this`~~ ~~and this~~. + +Code can also be shown in a block element. + +``` +foo := "bar"; +bar := "foo"; +``` + +Code can also use syntax highlighting. + +```go +func main() { + input := `var foo = "bar";` + + lexer := lexers.Get("javascript") + iterator, _ := lexer.Tokenise(nil, input) + style := styles.Get("github") + formatter := html.New(html.WithLineNumbers()) + + var buff bytes.Buffer + formatter.Format(&buff, style, iterator) + + fmt.Println(buff.String()) +} +``` + +``` +Long, single-line code blocks should not wrap. They should horizontally scroll if they are too long. This line should be long enough to demonstrate this. +``` + +Inline code inside table cells should still be distinguishable. + +| Language | Code | +|-------------|--------------------| +| Javascript | `var foo = "bar";` | +| Ruby | `foo = "bar"{` | + +---------------- + +Small images should be shown at their actual size. + +![](https://placekitten.com/g/300/200/) + +Large images should always scale down and fit in the content container. + +![](https://placekitten.com/g/1200/800/) + +## Components + +### Alerts + +{{< alert >}}This is an alert.{{< /alert >}} +{{< alert title="Note:" >}}This is an alert with a title.{{< /alert >}} +{{< alert type="success" >}}This is a successful alert.{{< /alert >}} +{{< alert type="warning" >}}This is a warning!{{< /alert >}} +{{< alert type="warning" title="Warning!" >}}This is a warning with a title!{{< /alert >}} + + +## Sizing + +Add some sections here to see how the ToC looks like. Bacon ipsum dolor sit amet t-bone doner shank drumstick, pork belly porchetta chuck sausage brisket ham hock rump pig. Chuck kielbasa leberkas, pork bresaola ham hock filet mignon cow shoulder short ribs biltong. + +### Parameters available + +Bacon ipsum dolor sit amet t-bone doner shank drumstick, pork belly porchetta chuck sausage brisket ham hock rump pig. Chuck kielbasa leberkas, pork bresaola ham hock filet mignon cow shoulder short ribs biltong. + +### Using pixels + +Bacon ipsum dolor sit amet t-bone doner shank drumstick, pork belly porchetta chuck sausage brisket ham hock rump pig. Chuck kielbasa leberkas, pork bresaola ham hock filet mignon cow shoulder short ribs biltong. + +### Using rem + +Bacon ipsum dolor sit amet t-bone doner shank drumstick, pork belly porchetta chuck sausage brisket ham hock rump pig. Chuck kielbasa leberkas, pork bresaola ham hock filet mignon cow shoulder short ribs biltong. + +## Memory + +Bacon ipsum dolor sit amet t-bone doner shank drumstick, pork belly porchetta chuck sausage brisket ham hock rump pig. Chuck kielbasa leberkas, pork bresaola ham hock filet mignon cow shoulder short ribs biltong. + +### RAM to use + +Bacon ipsum dolor sit amet t-bone doner shank drumstick, pork belly porchetta chuck sausage brisket ham hock rump pig. Chuck kielbasa leberkas, pork bresaola ham hock filet mignon cow shoulder short ribs biltong. + +### More is better + +Bacon ipsum dolor sit amet t-bone doner shank drumstick, pork belly porchetta chuck sausage brisket ham hock rump pig. Chuck kielbasa leberkas, pork bresaola ham hock filet mignon cow shoulder short ribs biltong. + +### Used RAM + +Bacon ipsum dolor sit amet t-bone doner shank drumstick, pork belly porchetta chuck sausage brisket ham hock rump pig. Chuck kielbasa leberkas, pork bresaola ham hock filet mignon cow shoulder short ribs biltong. + + + +``` +This is the final element on the page and there should be no margin below this. +``` diff --git a/doc-site/content/en/blog/releases/_index.md b/doc-site/content/en/blog/releases/_index.md new file mode 100644 index 0000000..b1d9eb4 --- /dev/null +++ b/doc-site/content/en/blog/releases/_index.md @@ -0,0 +1,8 @@ + +--- +title: "New Releases" +linkTitle: "Releases" +weight: 20 +--- + + diff --git a/doc-site/content/en/blog/releases/in-depth-monoliths-detailed-spec.md b/doc-site/content/en/blog/releases/in-depth-monoliths-detailed-spec.md new file mode 100755 index 0000000..ba8bd52 --- /dev/null +++ b/doc-site/content/en/blog/releases/in-depth-monoliths-detailed-spec.md @@ -0,0 +1,245 @@ + +--- +title: "Another Great Release" +linkTitle: "Release New Features" +date: 2018-01-04 +description: > + A short lead description about this content page. Text here can also be **bold** or _italic_ and can even be split over multiple paragraphs. +--- + +Text can be **bold**, _italic_, or ~~strikethrough~~. [Links](https://github.com) should be blue with no underlines (unless hovered over). + +There should be whitespace between paragraphs. There should be whitespace between paragraphs. There should be whitespace between paragraphs. There should be whitespace between paragraphs. + +There should be whitespace between paragraphs. There should be whitespace between paragraphs. There should be whitespace between paragraphs. There should be whitespace between paragraphs. + +> There should be no margin above this first sentence. +> +> Blockquotes should be a lighter gray with a border along the left side in the secondary color. +> +> There should be no margin below this final sentence. + +## First Header + +This is a normal paragraph following a header. Bacon ipsum dolor sit amet t-bone doner shank drumstick, pork belly porchetta chuck sausage brisket ham hock rump pig. Chuck kielbasa leberkas, pork bresaola ham hock filet mignon cow shoulder short ribs biltong. Bacon ipsum dolor sit amet t-bone doner shank drumstick, pork belly porchetta chuck sausage brisket ham hock rump pig. Chuck kielbasa leberkas, pork bresaola ham hock filet mignon cow shoulder short ribs biltong. Bacon ipsum dolor sit amet t-bone doner shank drumstick, pork belly porchetta chuck sausage brisket ham hock rump pig. Chuck kielbasa leberkas, pork bresaola ham hock filet mignon cow shoulder short ribs biltong. + + + +Bacon ipsum dolor sit amet t-bone doner shank drumstick, pork belly porchetta chuck sausage brisket ham hock rump pig. Chuck kielbasa leberkas, pork bresaola ham hock filet mignon cow shoulder short ribs biltong. + +On big screens, paragraphs and headings should not take up the full container width, but we want tables, code blocks and similar to take the full width. + +Lorem markdownum tuta hospes stabat; idem saxum facit quaterque repetito +occumbere, oves novem gestit haerebat frena; qui. Respicit recurvam erat: +pignora hinc reppulit nos **aut**, aptos, ipsa. + +Meae optatos *passa est* Epiros utiliter *Talibus niveis*, hoc lata, edidit. +Dixi ad aestum. + +## Header 2 + +> This is a blockquote following a header. Bacon ipsum dolor sit amet t-bone doner shank drumstick, pork belly porchetta chuck sausage brisket ham hock rump pig. Chuck kielbasa leberkas, pork bresaola ham hock filet mignon cow shoulder short ribs biltong. + +### Header 3 + +``` +This is a code block following a header. +``` + +#### Header 4 + +* This is an unordered list following a header. +* This is an unordered list following a header. +* This is an unordered list following a header. + +##### Header 5 + +1. This is an ordered list following a header. +2. This is an ordered list following a header. +3. This is an ordered list following a header. + +###### Header 6 + +| What | Follows | +|-----------|-----------------| +| A table | A header | +| A table | A header | +| A table | A header | + +---------------- + +There's a horizontal rule above and below this. + +---------------- + +Here is an unordered list: + +* Salt-n-Pepa +* Bel Biv DeVoe +* Kid 'N Play + +And an ordered list: + +1. Michael Jackson +2. Michael Bolton +3. Michael Bublé + +And an unordered task list: + +- [x] Create a sample markdown document +- [x] Add task lists to it +- [ ] Take a vacation + +And a "mixed" task list: + +- [ ] Steal underpants +- ? +- [ ] Profit! + +And a nested list: + +* Jackson 5 + * Michael + * Tito + * Jackie + * Marlon + * Jermaine +* TMNT + * Leonardo + * Michelangelo + * Donatello + * Raphael + +Definition lists can be used with Markdown syntax. Definition terms are bold. + +Name +: Godzilla + +Born +: 1952 + +Birthplace +: Japan + +Color +: Green + + +---------------- + +Tables should have bold headings and alternating shaded rows. + +| Artist | Album | Year | +|-------------------|-----------------|------| +| Michael Jackson | Thriller | 1982 | +| Prince | Purple Rain | 1984 | +| Beastie Boys | License to Ill | 1986 | + +If a table is too wide, it should scroll horizontally. + +| Artist | Album | Year | Label | Awards | Songs | +|-------------------|-----------------|------|-------------|----------|-----------| +| Michael Jackson | Thriller | 1982 | Epic Records | Grammy Award for Album of the Year, American Music Award for Favorite Pop/Rock Album, American Music Award for Favorite Soul/R&B Album, Brit Award for Best Selling Album, Grammy Award for Best Engineered Album, Non-Classical | Wanna Be Startin' Somethin', Baby Be Mine, The Girl Is Mine, Thriller, Beat It, Billie Jean, Human Nature, P.Y.T. (Pretty Young Thing), The Lady in My Life | +| Prince | Purple Rain | 1984 | Warner Brothers Records | Grammy Award for Best Score Soundtrack for Visual Media, American Music Award for Favorite Pop/Rock Album, American Music Award for Favorite Soul/R&B Album, Brit Award for Best Soundtrack/Cast Recording, Grammy Award for Best Rock Performance by a Duo or Group with Vocal | Let's Go Crazy, Take Me With U, The Beautiful Ones, Computer Blue, Darling Nikki, When Doves Cry, I Would Die 4 U, Baby I'm a Star, Purple Rain | +| Beastie Boys | License to Ill | 1986 | Mercury Records | noawardsbutthistablecelliswide | Rhymin & Stealin, The New Style, She's Crafty, Posse in Effect, Slow Ride, Girls, (You Gotta) Fight for Your Right, No Sleep Till Brooklyn, Paul Revere, Hold It Now, Hit It, Brass Monkey, Slow and Low, Time to Get Ill | + +---------------- + +Code snippets like `var foo = "bar";` can be shown inline. + +Also, `this should vertically align` ~~`with this`~~ ~~and this~~. + +Code can also be shown in a block element. + +``` +foo := "bar"; +bar := "foo"; +``` + +Code can also use syntax highlighting. + +```go +func main() { + input := `var foo = "bar";` + + lexer := lexers.Get("javascript") + iterator, _ := lexer.Tokenise(nil, input) + style := styles.Get("github") + formatter := html.New(html.WithLineNumbers()) + + var buff bytes.Buffer + formatter.Format(&buff, style, iterator) + + fmt.Println(buff.String()) +} +``` + +``` +Long, single-line code blocks should not wrap. They should horizontally scroll if they are too long. This line should be long enough to demonstrate this. +``` + +Inline code inside table cells should still be distinguishable. + +| Language | Code | +|-------------|--------------------| +| Javascript | `var foo = "bar";` | +| Ruby | `foo = "bar"{` | + +---------------- + +Small images should be shown at their actual size. + +![](https://placekitten.com/g/300/200/) + +Large images should always scale down and fit in the content container. + +![](https://placekitten.com/g/1200/800/) + +## Components + +### Alerts + +{{< alert >}}This is an alert.{{< /alert >}} +{{< alert title="Note:" >}}This is an alert with a title.{{< /alert >}} +{{< alert type="success" >}}This is a successful alert.{{< /alert >}} +{{< alert type="warning" >}}This is a warning!{{< /alert >}} +{{< alert type="warning" title="Warning!" >}}This is a warning with a title!{{< /alert >}} + + +## Sizing + +Add some sections here to see how the ToC looks like. Bacon ipsum dolor sit amet t-bone doner shank drumstick, pork belly porchetta chuck sausage brisket ham hock rump pig. Chuck kielbasa leberkas, pork bresaola ham hock filet mignon cow shoulder short ribs biltong. + +### Parameters available + +Bacon ipsum dolor sit amet t-bone doner shank drumstick, pork belly porchetta chuck sausage brisket ham hock rump pig. Chuck kielbasa leberkas, pork bresaola ham hock filet mignon cow shoulder short ribs biltong. + +### Using pixels + +Bacon ipsum dolor sit amet t-bone doner shank drumstick, pork belly porchetta chuck sausage brisket ham hock rump pig. Chuck kielbasa leberkas, pork bresaola ham hock filet mignon cow shoulder short ribs biltong. + +### Using rem + +Bacon ipsum dolor sit amet t-bone doner shank drumstick, pork belly porchetta chuck sausage brisket ham hock rump pig. Chuck kielbasa leberkas, pork bresaola ham hock filet mignon cow shoulder short ribs biltong. + +## Memory + +Bacon ipsum dolor sit amet t-bone doner shank drumstick, pork belly porchetta chuck sausage brisket ham hock rump pig. Chuck kielbasa leberkas, pork bresaola ham hock filet mignon cow shoulder short ribs biltong. + +### RAM to use + +Bacon ipsum dolor sit amet t-bone doner shank drumstick, pork belly porchetta chuck sausage brisket ham hock rump pig. Chuck kielbasa leberkas, pork bresaola ham hock filet mignon cow shoulder short ribs biltong. + +### More is better + +Bacon ipsum dolor sit amet t-bone doner shank drumstick, pork belly porchetta chuck sausage brisket ham hock rump pig. Chuck kielbasa leberkas, pork bresaola ham hock filet mignon cow shoulder short ribs biltong. + +### Used RAM + +Bacon ipsum dolor sit amet t-bone doner shank drumstick, pork belly porchetta chuck sausage brisket ham hock rump pig. Chuck kielbasa leberkas, pork bresaola ham hock filet mignon cow shoulder short ribs biltong. + + + +``` +This is the final element on the page and there should be no margin below this. +``` diff --git a/doc-site/content/en/code-example.md b/doc-site/content/en/code-example.md new file mode 100644 index 0000000..6a10102 --- /dev/null +++ b/doc-site/content/en/code-example.md @@ -0,0 +1,148 @@ +--- +title: "Code Example" +language: "typescript" +weight: 30 +--- + +We can illustrate how Behavior Graph code works in more detail through another example application, a typical login screen. +_This is just a walkthrough, please use the tutorials for a complete guide to learning Behavior Graph._ + +![Login Page]({{< static "images/login-ui-2.svg" >}}) + +As a first feature, we would like the Login button to remain disabled until the user has entered both a reasonable email and password. +If the user types in some password but an invalid email address (missing the '@' character, for example) the Login button will remain disabled. +Once she corrects the email address by adding an '@' character, the Login button should immediately enable. + +In Behavior Graph, this unit of functionality constitutes a typical *behavior*. +It looks like this + +{{< highlight javascript "hl_lines=1-9">}} +this.behavior() + .supplies(this.loginEnabled) + .demands(this.email, this.password) + .runs(() => { + const emailValid = this.validEmailAddress(this.email.value); + const passwordValid = this.password.value.length > 0; + const enabled = emailValid && passwordValid; + this.loginEnabled.update(enabled); + }); +{{< /highlight >}} + +Behaviors have dependencies on units of information called *resources*. +This behavior depends on two resources, `email` and `password`. +They appear as parameter of the `demands()` clause of `behavior()`. +This list is called the behavior's *demands*. +Our behavior has read only access to these resources. + +As stated before, behaviors are never called directly. +In specifying a behavior's demands, we are saying, _"whenever any of these resources updates (changes), then this behavior needs to run"._ +In our example, when either `email` or `password` (or both) update, this behavior will run in response. + +`email` and `password` are a specific type of resource called a *state resource* which is designed for saving and retrieving information. +The contents of these state resources are available via their `value` property. + +The block of code specified in the behavior is the code that will run. +A typical behavior uses normal code to perform its work. +Here we check the validity of the email with a normal function. +We determine if the Login button should be enabled using normal Boolean logic. + +This behavior is responsible for the enabled state of the Login button. +This information is stored in another state resource called `loginEnabled`. +We specify a behavior's responsibilities in the `supplies()` clause of `behavior()`. +This list is called the behavior's *supplies*. +A behavior can read and write the contents of its supplies. +The contents of a state resource can be written to by calling its `{{< term "update-method" >}}` method. + +We can continue to develop our Login page by adding a second feature. +When the user clicks the Login button and we are not already logging in, then we would like to enter into a logging in state. +In order to prevent mistakes, when we are in a logging in state, we would also like the Login button to be disabled. + +To implement this new feature we introduce a second behavior and make a small change to our existing behavior. + +{{< highlight javascript "hl_lines=1-9 12 16">}} +this.behavior() + .supplies(this.loggingIn) + .demands(this.loginClick) + .runs(() => { + if (this.loginClick.justUpdated && !this.loggingIn.value) { + this.loggingIn.update(true); + } + }); + +this.behavior() + .supplies(this.loginEnabled) + .demands(this.email, this.password, this.loggingIn) + .runs(() => { + const emailValid = this.validEmailAddress(this.email.value); + const passwordValid = this.password.value.length > 0; + const enabled = emailValid && passwordValid & !this.loggingIn.value; + this.loginEnabled.update(enabled); + }) +{{< /highlight >}} + +The new behavior has one demand, `loginClick`. +This is a second type of resource called a *moment resource*. +Moments are designed to track momentary happenings such as a button click or network call returning. +We can check if a moment has just happened by accessing its `{{< term "momentjustupdated-method" >}}` property. + +When the user clicks on the button, `loginClick` will update, and this new behavior will run. +It performs a simple Boolean check to determine if the `loggingIn` state resource needs to update to `{{< term "true-bool" >}}`. +It is allowed to update this resource because `loggingIn` is part of its supplies. + +We also modified our previous behavior to include `loggingIn` as one of its demands. +This means it will run when the `loggingIn` resource updates as well as have permission to access the Boolean `value` of `loggingIn`. +Now the state of `loginEnabled` depends on all three pieces of information: `email`, `password`, and `loggingIn`. + +## Actions + +![Login Behavior Graph]({{< static "images/login-intro-graph.svg" >}}) + +Information comes into our system via *actions*. +A typical UI library will provide some type of callback or event system to capture user inputs. +In this example we will listen to a click handler to create a new action which updates the `loginClick` moment resource. + +{{< highlight javascript >}} +this.loginButton.onClick = () => { + this.action(() => { + this.loginClick.update(); + }); +}; +{{< /highlight >}} + +We would similarly connect `email` and `password` to their respective text fields. + +Once the user has entered a valid email and password, the Login button will enable. +When the user subsequently clicks on the Login button, the behavior that supplies `loggingIn` will run. +It will update the `loggingIn` resource to `{{< term "true-bool" >}}`. +This in turn will cause the behavior that supplies `loginEnabled` behavior to run. +It will update the `loginEnabled` resource to `{{< term "false-bool" >}}`. + +## Side Effects + +In order to perform real output to the UI library, we need to create a *side effect*. + +{{< highlight javascript "hl_lines=10-12">}} +this.behavior() + .supplies(this.loginEnabled) + .demands(this.email, this.password, this.loggingIn) + .runs(() => { + const emailValid = this.validEmailAddress(this.email.value); + const passwordValid = this.password.value.length > 0; + const enabled = emailValid && passwordValid & !this.loggingIn.value; + this.loginEnabled.update(enabled); + + this.sideEffect(() => { + this.loginButton.enabled = this.loginEnabled.value; + }); + }) +{{< /highlight >}} + +Side effects are created directly inside behaviors. +This side effect updates the `enabled` state of the `loginButton` based on the state of the `loginEnabled` resource. +It does not run immediately, however. +Behavior Graph defers the running of side effects until after all behaviors have run. +Side effects are a practical way for Behavior Graph to create output while ensuring access to consistent state. + +This example covers the primary concepts when developing with Behavior Graph. +There are, however, additional features that make Behavior Graph a practical software library. +_Please work through the tutorials for a full coverage of the core features._ diff --git a/doc-site/content/en/community/_index.md b/doc-site/content/en/community/_index.md new file mode 100644 index 0000000..cdade16 --- /dev/null +++ b/doc-site/content/en/community/_index.md @@ -0,0 +1,8 @@ +--- +title: Community +menu: + main: + weight: 40 +--- + + diff --git a/doc-site/content/en/docs2/Concepts/_index.md b/doc-site/content/en/docs2/Concepts/_index.md new file mode 100644 index 0000000..6cc6420 --- /dev/null +++ b/doc-site/content/en/docs2/Concepts/_index.md @@ -0,0 +1,17 @@ +--- +title: "Concepts" +linkTitle: "Concepts" +weight: 4 +description: > + What does your user need to understand about your project in order to use it - or potentially contribute to it? +--- + +{{% pageinfo %}} +This is a placeholder page that shows you how to use this template site. +{{% /pageinfo %}} + +For many projects, users may not need much information beyond the information in the [Overview](/docs/overview/), so this section is **optional**. However if there are areas where your users will need a more detailed understanding of a given term or feature in order to do anything useful with your project (or to not make mistakes when using it) put that information in this section. For example, you may want to add some conceptual pages if you have a large project with many components and a complex architecture. + +Remember to focus on what the user needs to know, not just what you think is interesting about your project! If they don’t need to understand your original design decisions to use or contribute to the project, don’t put them in, or include your design docs in your repo and link to them. Similarly, most users will probably need to know more about how features work when in use rather than how they are implemented. Consider a separate architecture page for more detailed implementation and system design information that potential project contributors can consult. + + diff --git a/doc-site/content/en/docs2/Contribution guidelines/_index.md b/doc-site/content/en/docs2/Contribution guidelines/_index.md new file mode 100644 index 0000000..bdf7078 --- /dev/null +++ b/doc-site/content/en/docs2/Contribution guidelines/_index.md @@ -0,0 +1,81 @@ +--- +title: "Contribution Guidelines" +linkTitle: "Contribution Guidelines" +weight: 10 +description: > + How to contribute to the docs +--- + +{{% pageinfo %}} +These basic sample guidelines assume that your Docsy site is deployed using Netlify and your files are stored in GitHub. You can use the guidelines "as is" or adapt them with your own instructions: for example, other deployment options, information about your doc project's file structure, project-specific review guidelines, versioning guidelines, or any other information your users might find useful when updating your site. [Kubeflow](https://github.com/kubeflow/website/blob/master/README.md) has a great example. + +Don't forget to link to your own doc repo rather than our example site! Also make sure users can find these guidelines from your doc repo README: either add them there and link to them from this page, add them here and link to them from the README, or include them in both locations. +{{% /pageinfo %}} + +We use [Hugo](https://gohugo.io/) to format and generate our website, the +[Docsy](https://github.com/google/docsy) theme for styling and site structure, +and [Netlify](https://www.netlify.com/) to manage the deployment of the site. +Hugo is an open-source static site generator that provides us with templates, +content organisation in a standard directory structure, and a website generation +engine. You write the pages in Markdown (or HTML if you want), and Hugo wraps them up into a website. + +All submissions, including submissions by project members, require review. We +use GitHub pull requests for this purpose. Consult +[GitHub Help](https://help.github.com/articles/about-pull-requests/) for more +information on using pull requests. + +## Quick start with Netlify + +Here's a quick guide to updating the docs. It assumes you're familiar with the +GitHub workflow and you're happy to use the automated preview of your doc +updates: + +1. Fork the [Goldydocs repo](https://github.com/google/docsy-example) on GitHub. +1. Make your changes and send a pull request (PR). +1. If you're not yet ready for a review, add "WIP" to the PR name to indicate + it's a work in progress. (**Don't** add the Hugo property + "draft = true" to the page front matter, because that prevents the + auto-deployment of the content preview described in the next point.) +1. Wait for the automated PR workflow to do some checks. When it's ready, + you should see a comment like this: **deploy/netlify — Deploy preview ready!** +1. Click **Details** to the right of "Deploy preview ready" to see a preview + of your updates. +1. Continue updating your doc and pushing your changes until you're happy with + the content. +1. When you're ready for a review, add a comment to the PR, and remove any + "WIP" markers. + +## Updating a single page + +If you've just spotted something you'd like to change while using the docs, Docsy has a shortcut for you: + +1. Click **Edit this page** in the top right hand corner of the page. +1. If you don't already have an up to date fork of the project repo, you are prompted to get one - click **Fork this repository and propose changes** or **Update your Fork** to get an up to date version of the project to edit. The appropriate page in your fork is displayed in edit mode. +1. Follow the rest of the [Quick start with Netlify](#quick-start-with-netlify) process above to make, preview, and propose your changes. + +## Previewing your changes locally + +If you want to run your own local Hugo server to preview your changes as you work: + +1. Follow the instructions in [Getting started](/docs/getting-started) to install Hugo and any other tools you need. You'll need at least **Hugo version 0.45** (we recommend using the most recent available version), and it must be the **extended** version, which supports SCSS. +1. Fork the [Goldydocs repo](https://github.com/google/docsy-example) repo into your own project, then create a local copy using `git clone`. Don’t forget to use `--recurse-submodules` or you won’t pull down some of the code you need to generate a working site. + + ``` + git clone --recurse-submodules --depth 1 https://github.com/google/docsy-example.git + ``` + +1. Run `hugo server` in the site root directory. By default your site will be available at http://localhost:1313/. Now that you're serving your site locally, Hugo will watch for changes to the content and automatically refresh your site. +1. Continue with the usual GitHub workflow to edit files, commit them, push the + changes up to your fork, and create a pull request. + +## Creating an issue + +If you've found a problem in the docs, but you're not sure how to fix it yourself, please create an issue in the [Goldydocs repo](https://github.com/google/docsy-example/issues). You can also create an issue about a specific page by clicking the **Create Issue** button in the top right hand corner of the page. + +## Useful resources + +* [Docsy user guide](https://www.docsy.dev/docs/): All about Docsy, including how it manages navigation, look and feel, and multi-language support. +* [Hugo documentation](https://gohugo.io/documentation/): Comprehensive reference for Hugo. +* [Github Hello World!](https://guides.github.com/activities/hello-world/): A basic introduction to GitHub concepts and workflow. + + diff --git a/doc-site/content/en/docs2/Examples/_index.md b/doc-site/content/en/docs2/Examples/_index.md new file mode 100755 index 0000000..efc8cc8 --- /dev/null +++ b/doc-site/content/en/docs2/Examples/_index.md @@ -0,0 +1,17 @@ + +--- +title: "Examples" +linkTitle: "Examples" +weight: 3 +date: 2017-01-05 +description: > + See your project in action! +--- + +{{% pageinfo %}} +This is a placeholder page that shows you how to use this template site. +{{% /pageinfo %}} + +Do you have any example **applications** or **code** for your users in your repo or elsewhere? Link to your examples here. + + diff --git a/doc-site/content/en/docs2/Getting started/_index.md b/doc-site/content/en/docs2/Getting started/_index.md new file mode 100644 index 0000000..5a3bbc7 --- /dev/null +++ b/doc-site/content/en/docs2/Getting started/_index.md @@ -0,0 +1,37 @@ +--- +categories: ["Examples", "Placeholders"] +tags: ["test","docs"] +title: "Getting Started" +linkTitle: "Getting Started" +weight: 2 +description: > + What does your user need to know to try your project? +--- + +{{% pageinfo %}} +This is a placeholder page that shows you how to use this template site. +{{% /pageinfo %}} + +Information in this section helps your user try your project themselves. + +* What do your users need to do to start using your project? This could include downloading/installation instructions, including any prerequisites or system requirements. + +* Introductory “Hello World” example, if appropriate. More complex tutorials should live in the Tutorials section. + +Consider using the headings below for your getting started page. You can delete any that are not applicable to your project. + +## Prerequisites + +Are there any system requirements for using your project? What languages are supported (if any)? Do users need to already have any software or tools installed? + +## Installation + +Where can your user find your project code? How can they install it (binaries, installable package, build from source)? Are there multiple options/versions they can install and how should they choose the right one for them? + +## Setup + +Is there any initial setup users need to do after installation to try your project? + +## Try it out! + +Can your users test their installation, for example by running a command or deploying a Hello World example? diff --git a/doc-site/content/en/docs2/Getting started/example-page.md b/doc-site/content/en/docs2/Getting started/example-page.md new file mode 100644 index 0000000..0bdd56c --- /dev/null +++ b/doc-site/content/en/docs2/Getting started/example-page.md @@ -0,0 +1,241 @@ +--- +categories: ["Examples"] +tags: ["test", "sample", "docs"] +title: "Example Page" +linkTitle: "Example Page" +date: 2017-01-05 +description: > + A short lead description about this content page. It can be **bold** or _italic_ and can be split over multiple paragraphs. +--- + +{{% pageinfo %}} +This is a placeholder page. Replace it with your own content. +{{% /pageinfo %}} + + +Text can be **bold**, _italic_, or ~~strikethrough~~. [Links](https://gohugo.io) should be blue with no underlines (unless hovered over). + +There should be whitespace between paragraphs. Vape migas chillwave sriracha poutine try-hard distillery. Tattooed shabby chic small batch, pabst art party heirloom letterpress air plant pop-up. Sustainable chia skateboard art party banjo cardigan normcore affogato vexillologist quinoa meggings man bun master cleanse shoreditch readymade. Yuccie prism four dollar toast tbh cardigan iPhone, tumblr listicle live-edge VHS. Pug lyft normcore hot chicken biodiesel, actually keffiyeh thundercats photo booth pour-over twee fam food truck microdosing banh mi. Vice activated charcoal raclette unicorn live-edge post-ironic. Heirloom vexillologist coloring book, beard deep v letterpress echo park humblebrag tilde. + +90's four loko seitan photo booth gochujang freegan tumeric listicle fam ugh humblebrag. Bespoke leggings gastropub, biodiesel brunch pug fashion axe meh swag art party neutra deep v chia. Enamel pin fanny pack knausgaard tofu, artisan cronut hammock meditation occupy master cleanse chartreuse lumbersexual. Kombucha kogi viral truffaut synth distillery single-origin coffee ugh slow-carb marfa selfies. Pitchfork schlitz semiotics fanny pack, ugh artisan vegan vaporware hexagon. Polaroid fixie post-ironic venmo wolf ramps **kale chips**. + +> There should be no margin above this first sentence. +> +> Blockquotes should be a lighter gray with a border along the left side in the secondary color. +> +> There should be no margin below this final sentence. + +## First Header 2 + +This is a normal paragraph following a header. Knausgaard kale chips snackwave microdosing cronut copper mug swag synth bitters letterpress glossier **craft beer**. Mumblecore bushwick authentic gochujang vegan chambray meditation jean shorts irony. Viral farm-to-table kale chips, pork belly palo santo distillery activated charcoal aesthetic jianbing air plant woke lomo VHS organic. Tattooed locavore succulents heirloom, small batch sriracha echo park DIY af. Shaman you probably haven't heard of them copper mug, crucifix green juice vape *single-origin coffee* brunch actually. Mustache etsy vexillologist raclette authentic fam. Tousled beard humblebrag asymmetrical. I love turkey, I love my job, I love my friends, I love Chardonnay! + +Deae legum paulatimque terra, non vos mutata tacet: dic. Vocant docuique me plumas fila quin afuerunt copia haec o neque. + +On big screens, paragraphs and headings should not take up the full container width, but we want tables, code blocks and similar to take the full width. + +Scenester tumeric pickled, authentic crucifix post-ironic fam freegan VHS pork belly 8-bit yuccie PBR&B. **I love this life we live in**. + + +## Second Header 2 + +> This is a blockquote following a header. Bacon ipsum dolor sit amet t-bone doner shank drumstick, pork belly porchetta chuck sausage brisket ham hock rump pig. Chuck kielbasa leberkas, pork bresaola ham hock filet mignon cow shoulder short ribs biltong. + +### Header 3 + +``` +This is a code block following a header. +``` + +Next level leggings before they sold out, PBR&B church-key shaman echo park. Kale chips occupy godard whatever pop-up freegan pork belly selfies. Gastropub Belinda subway tile woke post-ironic seitan. Shabby chic man bun semiotics vape, chia messenger bag plaid cardigan. + +#### Header 4 + +* This is an unordered list following a header. +* This is an unordered list following a header. +* This is an unordered list following a header. + +##### Header 5 + +1. This is an ordered list following a header. +2. This is an ordered list following a header. +3. This is an ordered list following a header. + +###### Header 6 + +| What | Follows | +|-----------|-----------------| +| A table | A header | +| A table | A header | +| A table | A header | + +---------------- + +There's a horizontal rule above and below this. + +---------------- + +Here is an unordered list: + +* Liverpool F.C. +* Chelsea F.C. +* Manchester United F.C. + +And an ordered list: + +1. Michael Brecker +2. Seamus Blake +3. Branford Marsalis + +And an unordered task list: + +- [x] Create a Hugo theme +- [x] Add task lists to it +- [ ] Take a vacation + +And a "mixed" task list: + +- [ ] Pack bags +- ? +- [ ] Travel! + +And a nested list: + +* Jackson 5 + * Michael + * Tito + * Jackie + * Marlon + * Jermaine +* TMNT + * Leonardo + * Michelangelo + * Donatello + * Raphael + +Definition lists can be used with Markdown syntax. Definition headers are bold. + +Name +: Godzilla + +Born +: 1952 + +Birthplace +: Japan + +Color +: Green + + +---------------- + +Tables should have bold headings and alternating shaded rows. + +| Artist | Album | Year | +|-------------------|-----------------|------| +| Michael Jackson | Thriller | 1982 | +| Prince | Purple Rain | 1984 | +| Beastie Boys | License to Ill | 1986 | + +If a table is too wide, it should scroll horizontally. + +| Artist | Album | Year | Label | Awards | Songs | +|-------------------|-----------------|------|-------------|----------|-----------| +| Michael Jackson | Thriller | 1982 | Epic Records | Grammy Award for Album of the Year, American Music Award for Favorite Pop/Rock Album, American Music Award for Favorite Soul/R&B Album, Brit Award for Best Selling Album, Grammy Award for Best Engineered Album, Non-Classical | Wanna Be Startin' Somethin', Baby Be Mine, The Girl Is Mine, Thriller, Beat It, Billie Jean, Human Nature, P.Y.T. (Pretty Young Thing), The Lady in My Life | +| Prince | Purple Rain | 1984 | Warner Brothers Records | Grammy Award for Best Score Soundtrack for Visual Media, American Music Award for Favorite Pop/Rock Album, American Music Award for Favorite Soul/R&B Album, Brit Award for Best Soundtrack/Cast Recording, Grammy Award for Best Rock Performance by a Duo or Group with Vocal | Let's Go Crazy, Take Me With U, The Beautiful Ones, Computer Blue, Darling Nikki, When Doves Cry, I Would Die 4 U, Baby I'm a Star, Purple Rain | +| Beastie Boys | License to Ill | 1986 | Mercury Records | noawardsbutthistablecelliswide | Rhymin & Stealin, The New Style, She's Crafty, Posse in Effect, Slow Ride, Girls, (You Gotta) Fight for Your Right, No Sleep Till Brooklyn, Paul Revere, Hold It Now, Hit It, Brass Monkey, Slow and Low, Time to Get Ill | + +---------------- + +Code snippets like `var foo = "bar";` can be shown inline. + +Also, `this should vertically align` ~~`with this`~~ ~~and this~~. + +Code can also be shown in a block element. + +``` +foo := "bar"; +bar := "foo"; +``` + +Code can also use syntax highlighting. + +```go +func main() { + input := `var foo = "bar";` + + lexer := lexers.Get("javascript") + iterator, _ := lexer.Tokenise(nil, input) + style := styles.Get("github") + formatter := html.New(html.WithLineNumbers()) + + var buff bytes.Buffer + formatter.Format(&buff, style, iterator) + + fmt.Println(buff.String()) +} +``` + +``` +Long, single-line code blocks should not wrap. They should horizontally scroll if they are too long. This line should be long enough to demonstrate this. +``` + +Inline code inside table cells should still be distinguishable. + +| Language | Code | +|-------------|--------------------| +| Javascript | `var foo = "bar";` | +| Ruby | `foo = "bar"{` | + +---------------- + +Small images should be shown at their actual size. + +![](https://upload.wikimedia.org/wikipedia/commons/thumb/9/9e/Picea_abies_shoot_with_buds%2C_Sogndal%2C_Norway.jpg/240px-Picea_abies_shoot_with_buds%2C_Sogndal%2C_Norway.jpg) + +Large images should always scale down and fit in the content container. + +![](https://upload.wikimedia.org/wikipedia/commons/thumb/9/9e/Picea_abies_shoot_with_buds%2C_Sogndal%2C_Norway.jpg/1024px-Picea_abies_shoot_with_buds%2C_Sogndal%2C_Norway.jpg) + +_The photo above of the Spruce Picea abies shoot with foliage buds: Bjørn Erik Pedersen, CC-BY-SA._ + + +## Components + +### Alerts + +{{< alert >}}This is an alert.{{< /alert >}} +{{< alert title="Note" >}}This is an alert with a title.{{< /alert >}} +{{% alert title="Note" %}}This is an alert with a title and **Markdown**.{{% /alert %}} +{{< alert color="success" >}}This is a successful alert.{{< /alert >}} +{{< alert color="warning" >}}This is a warning.{{< /alert >}} +{{< alert color="warning" title="Warning" >}}This is a warning with a title.{{< /alert >}} + + +## Another Heading + +Add some sections here to see how the ToC looks like. Bacon ipsum dolor sit amet t-bone doner shank drumstick, pork belly porchetta chuck sausage brisket ham hock rump pig. Chuck kielbasa leberkas, pork bresaola ham hock filet mignon cow shoulder short ribs biltong. + +### This Document + +Inguina genus: Anaphen post: lingua violente voce suae meus aetate diversi. Orbis unam nec flammaeque status deam Silenum erat et a ferrea. Excitus rigidum ait: vestro et Herculis convicia: nitidae deseruit coniuge Proteaque adiciam *eripitur*? Sitim noceat signa *probat quidem*. Sua longis *fugatis* quidem genae. + + +### Pixel Count + +Tilde photo booth wayfarers cliche lomo intelligentsia man braid kombucha vaporware farm-to-table mixtape portland. PBR&B pickled cornhole ugh try-hard ethical subway tile. Fixie paleo intelligentsia pabst. Ennui waistcoat vinyl gochujang. Poutine salvia authentic affogato, chambray lumbersexual shabby chic. + +### Contact Info + +Plaid hell of cred microdosing, succulents tilde pour-over. Offal shabby chic 3 wolf moon blue bottle raw denim normcore poutine pork belly. + + +### External Links + +Stumptown PBR&B keytar plaid street art, forage XOXO pitchfork selvage affogato green juice listicle pickled everyday carry hashtag. Organic sustainable letterpress sartorial scenester intelligentsia swag bushwick. Put a bird on it stumptown neutra locavore. IPhone typewriter messenger bag narwhal. Ennui cold-pressed seitan flannel keytar, single-origin coffee adaptogen occupy yuccie williamsburg chillwave shoreditch forage waistcoat. + + + +``` +This is the final element on the page and there should be no margin below this. +``` diff --git a/doc-site/content/en/docs2/Overview/_index.md b/doc-site/content/en/docs2/Overview/_index.md new file mode 100644 index 0000000..6a03756 --- /dev/null +++ b/doc-site/content/en/docs2/Overview/_index.md @@ -0,0 +1,38 @@ +--- +title: "Overview" +linkTitle: "Overview" +weight: 1 +description: > + Here's where your user finds out if your project is for them. +--- + +{{% pageinfo %}} +This is a placeholder page that shows you how to use this template site. +{{% /pageinfo %}} + + +The Overview is where your users find out about your project. Depending on the size of your docset, you can have a separate overview page (like this one) or put your overview contents in the Documentation landing page (like in the Docsy User Guide). + +Try answering these questions for your user in this page: + +## What is it? + +Introduce your project, including what it does or lets you do, why you would use it, and its primary goal (and how it achieves it). This should be similar to your README description, though you can go into a little more detail here if you want. + +## Why do I want it? + +Help your user know if your project will help them. Useful information can include: + +* **What is it good for?**: What types of problems does your project solve? What are the benefits of using it? + +* **What is it not good for?**: For example, point out situations that might intuitively seem suited for your project, but aren't for some reason. Also mention known limitations, scaling issues, or anything else that might let your users know if the project is not for them. + +* **What is it *not yet* good for?**: Highlight any useful features that are coming soon. + +## Where should I go next? + +Give your users next steps from the Overview. For example: + +* [Getting Started](/docs/getting-started/): Get started with $project +* [Examples](/docs/examples/): Check out some example code! + diff --git a/doc-site/content/en/docs2/Reference/_index.md b/doc-site/content/en/docs2/Reference/_index.md new file mode 100644 index 0000000..f174fc0 --- /dev/null +++ b/doc-site/content/en/docs2/Reference/_index.md @@ -0,0 +1,14 @@ +--- +title: "Reference" +linkTitle: "Reference" +weight: 9 +description: > + Low level reference docs for your project. +--- + +{{% pageinfo %}} +This is a placeholder page that shows you how to use this template site. +{{% /pageinfo %}} + +If your project has an API, configuration, or other reference - anything that users need to look up that’s at an even lower level than a single task - put (or link to it) here. You can serve and link to generated reference docs created using Doxygen, +Javadoc, or other doc generation tools by putting them in your `static/` directory. Find out more in [Adding static content](https://docsy.dev/docs/adding-content/content/#adding-static-content). For OpenAPI reference, Docsy also provides a [Swagger UI layout and shortcode](https://www.docsy.dev/docs/adding-content/shortcodes/#swaggerui) that renders [Swagger UI](https://swagger.io/tools/swagger-ui/) using any OpenAPI YAML or JSON file as source. diff --git a/doc-site/content/en/docs2/Reference/parameter-reference.md b/doc-site/content/en/docs2/Reference/parameter-reference.md new file mode 100644 index 0000000..0012c85 --- /dev/null +++ b/doc-site/content/en/docs2/Reference/parameter-reference.md @@ -0,0 +1,212 @@ +--- +title: "Parameter Reference" +linkTitle: "Parameter Reference" +date: 2017-01-05 +description: > + A short lead description about this content page. It can be **bold** or _italic_ and can be split over multiple paragraphs. +--- + +{{% pageinfo %}} +This is a placeholder page. Replace it with your own content. +{{% /pageinfo %}} + +Text can be **bold**, _italic_, or ~~strikethrough~~. [Links](https://gohugo.io) should be blue with no underlines (unless hovered over). + +There should be whitespace between paragraphs. Vape migas chillwave sriracha poutine try-hard distillery. Tattooed shabby chic small batch, pabst art party heirloom letterpress air plant pop-up. Sustainable chia skateboard art party banjo cardigan normcore affogato vexillologist quinoa meggings man bun master cleanse shoreditch readymade. Yuccie prism four dollar toast tbh cardigan iPhone, tumblr listicle live-edge VHS. Pug lyft normcore hot chicken biodiesel, actually keffiyeh thundercats photo booth pour-over twee fam food truck microdosing banh mi. Vice activated charcoal raclette unicorn live-edge post-ironic. Heirloom vexillologist coloring book, beard deep v letterpress echo park humblebrag tilde. + +90's four loko seitan photo booth gochujang freegan tumeric listicle fam ugh humblebrag. Bespoke leggings gastropub, biodiesel brunch pug fashion axe meh swag art party neutra deep v chia. Enamel pin fanny pack knausgaard tofu, artisan cronut hammock meditation occupy master cleanse chartreuse lumbersexual. Kombucha kogi viral truffaut synth distillery single-origin coffee ugh slow-carb marfa selfies. Pitchfork schlitz semiotics fanny pack, ugh artisan vegan vaporware hexagon. Polaroid fixie post-ironic venmo wolf ramps **kale chips**. + +> There should be no margin above this first sentence. +> +> Blockquotes should be a lighter gray with a border along the left side in the secondary color. +> +> There should be no margin below this final sentence. + +## First Header 2 + +This is a normal paragraph following a header. Knausgaard kale chips snackwave microdosing cronut copper mug swag synth bitters letterpress glossier **craft beer**. Mumblecore bushwick authentic gochujang vegan chambray meditation jean shorts irony. Viral farm-to-table kale chips, pork belly palo santo distillery activated charcoal aesthetic jianbing air plant woke lomo VHS organic. Tattooed locavore succulents heirloom, small batch sriracha echo park DIY af. Shaman you probably haven't heard of them copper mug, crucifix green juice vape *single-origin coffee* brunch actually. Mustache etsy vexillologist raclette authentic fam. Tousled beard humblebrag asymmetrical. I love turkey, I love my job, I love my friends, I love Chardonnay! + +Deae legum paulatimque terra, non vos mutata tacet: dic. Vocant docuique me plumas fila quin afuerunt copia haec o neque. + +On big screens, paragraphs and headings should not take up the full container width, but we want tables, code blocks and similar to take the full width. + +Scenester tumeric pickled, authentic crucifix post-ironic fam freegan VHS pork belly 8-bit yuccie PBR&B. **I love this life we live in**. + + +## Second Header 2 + +> This is a blockquote following a header. Bacon ipsum dolor sit amet t-bone doner shank drumstick, pork belly porchetta chuck sausage brisket ham hock rump pig. Chuck kielbasa leberkas, pork bresaola ham hock filet mignon cow shoulder short ribs biltong. + +### Header 3 + +``` +This is a code block following a header. +``` + +Next level leggings before they sold out, PBR&B church-key shaman echo park. Kale chips occupy godard whatever pop-up freegan pork belly selfies. Gastropub Belinda subway tile woke post-ironic seitan. Shabby chic man bun semiotics vape, chia messenger bag plaid cardigan. + +#### Header 4 + +* This is an unordered list following a header. +* This is an unordered list following a header. +* This is an unordered list following a header. + +##### Header 5 + +1. This is an ordered list following a header. +2. This is an ordered list following a header. +3. This is an ordered list following a header. + +###### Header 6 + +| What | Follows | +|-----------|-----------------| +| A table | A header | +| A table | A header | +| A table | A header | + +---------------- + +There's a horizontal rule above and below this. + +---------------- + +Here is an unordered list: + +* Liverpool F.C. +* Chelsea F.C. +* Manchester United F.C. + +And an ordered list: + +1. Michael Brecker +2. Seamus Blake +3. Branford Marsalis + +And an unordered task list: + +- [x] Create a Hugo theme +- [x] Add task lists to it +- [ ] Take a vacation + +And a "mixed" task list: + +- [ ] Pack bags +- ? +- [ ] Travel! + +And a nested list: + +* Jackson 5 + * Michael + * Tito + * Jackie + * Marlon + * Jermaine +* TMNT + * Leonardo + * Michelangelo + * Donatello + * Raphael + +Definition lists can be used with Markdown syntax. Definition headers are bold. + +Name +: Godzilla + +Born +: 1952 + +Birthplace +: Japan + +Color +: Green + + +---------------- + +Tables should have bold headings and alternating shaded rows. + +| Artist | Album | Year | +|-------------------|-----------------|------| +| Michael Jackson | Thriller | 1982 | +| Prince | Purple Rain | 1984 | +| Beastie Boys | License to Ill | 1986 | + +If a table is too wide, it should scroll horizontally. + +| Artist | Album | Year | Label | Awards | Songs | +|-------------------|-----------------|------|-------------|----------|-----------| +| Michael Jackson | Thriller | 1982 | Epic Records | Grammy Award for Album of the Year, American Music Award for Favorite Pop/Rock Album, American Music Award for Favorite Soul/R&B Album, Brit Award for Best Selling Album, Grammy Award for Best Engineered Album, Non-Classical | Wanna Be Startin' Somethin', Baby Be Mine, The Girl Is Mine, Thriller, Beat It, Billie Jean, Human Nature, P.Y.T. (Pretty Young Thing), The Lady in My Life | +| Prince | Purple Rain | 1984 | Warner Brothers Records | Grammy Award for Best Score Soundtrack for Visual Media, American Music Award for Favorite Pop/Rock Album, American Music Award for Favorite Soul/R&B Album, Brit Award for Best Soundtrack/Cast Recording, Grammy Award for Best Rock Performance by a Duo or Group with Vocal | Let's Go Crazy, Take Me With U, The Beautiful Ones, Computer Blue, Darling Nikki, When Doves Cry, I Would Die 4 U, Baby I'm a Star, Purple Rain | +| Beastie Boys | License to Ill | 1986 | Mercury Records | noawardsbutthistablecelliswide | Rhymin & Stealin, The New Style, She's Crafty, Posse in Effect, Slow Ride, Girls, (You Gotta) Fight for Your Right, No Sleep Till Brooklyn, Paul Revere, Hold It Now, Hit It, Brass Monkey, Slow and Low, Time to Get Ill | + +---------------- + +Code snippets like `var foo = "bar";` can be shown inline. + +Also, `this should vertically align` ~~`with this`~~ ~~and this~~. + +Code can also be shown in a block element. + +``` +foo := "bar"; +bar := "foo"; +``` + +Code can also use syntax highlighting. + +```go +func main() { + input := `var foo = "bar";` + + lexer := lexers.Get("javascript") + iterator, _ := lexer.Tokenise(nil, input) + style := styles.Get("github") + formatter := html.New(html.WithLineNumbers()) + + var buff bytes.Buffer + formatter.Format(&buff, style, iterator) + + fmt.Println(buff.String()) +} +``` + +``` +Long, single-line code blocks should not wrap. They should horizontally scroll if they are too long. This line should be long enough to demonstrate this. +``` + +Inline code inside table cells should still be distinguishable. + +| Language | Code | +|-------------|--------------------| +| Javascript | `var foo = "bar";` | +| Ruby | `foo = "bar"{` | + +---------------- + +Small images should be shown at their actual size. + +![](https://upload.wikimedia.org/wikipedia/commons/thumb/9/9e/Picea_abies_shoot_with_buds%2C_Sogndal%2C_Norway.jpg/240px-Picea_abies_shoot_with_buds%2C_Sogndal%2C_Norway.jpg) + +Large images should always scale down and fit in the content container. + +![](https://upload.wikimedia.org/wikipedia/commons/thumb/9/9e/Picea_abies_shoot_with_buds%2C_Sogndal%2C_Norway.jpg/1024px-Picea_abies_shoot_with_buds%2C_Sogndal%2C_Norway.jpg) + +_The photo above of the Spruce Picea abies shoot with foliage buds: Bjørn Erik Pedersen, CC-BY-SA._ + + +## Components + +### Alerts + +{{< alert >}}This is an alert.{{< /alert >}} +{{< alert title="Note" >}}This is an alert with a title.{{< /alert >}} +{{% alert title="Note" %}}This is an alert with a title and **Markdown**.{{% /alert %}} +{{< alert color="success" >}}This is a successful alert.{{< /alert >}} +{{< alert color="warning" >}}This is a warning.{{< /alert >}} +{{< alert color="warning" title="Warning" >}}This is a warning with a title.{{< /alert >}} + + +## Another Heading diff --git a/doc-site/content/en/docs2/Tasks/Ponycopters/_index.md b/doc-site/content/en/docs2/Tasks/Ponycopters/_index.md new file mode 100755 index 0000000..a1bd522 --- /dev/null +++ b/doc-site/content/en/docs2/Tasks/Ponycopters/_index.md @@ -0,0 +1,16 @@ + +--- +title: "Working with Ponycopters" +linkTitle: "Working with Ponycopters" +date: 2017-01-05 +description: > + A short lead description about this section page. Text here can also be **bold** or _italic_ and can even be split over multiple paragraphs. +--- + +{{% pageinfo %}} +This is a placeholder page. Replace it with your own content. +{{% /pageinfo %}} + + +This is the section landing page. + diff --git a/doc-site/content/en/docs2/Tasks/Ponycopters/configuring-ponycopters.md b/doc-site/content/en/docs2/Tasks/Ponycopters/configuring-ponycopters.md new file mode 100644 index 0000000..6f29172 --- /dev/null +++ b/doc-site/content/en/docs2/Tasks/Ponycopters/configuring-ponycopters.md @@ -0,0 +1,239 @@ +--- +title: "Configuring Ponycopters" +linkTitle: "Configuring Ponycopters" +date: 2017-01-05 +weight: 2 +description: > + A short lead description about this content page. It can be **bold** or _italic_ and can be split over multiple paragraphs. +--- + +{{% pageinfo %}} +This is a placeholder page. Replace it with your own content. +{{% /pageinfo %}} + +Text can be **bold**, _italic_, or ~~strikethrough~~. [Links](https://gohugo.io) should be blue with no underlines (unless hovered over). + +There should be whitespace between paragraphs. Vape migas chillwave sriracha poutine try-hard distillery. Tattooed shabby chic small batch, pabst art party heirloom letterpress air plant pop-up. Sustainable chia skateboard art party banjo cardigan normcore affogato vexillologist quinoa meggings man bun master cleanse shoreditch readymade. Yuccie prism four dollar toast tbh cardigan iPhone, tumblr listicle live-edge VHS. Pug lyft normcore hot chicken biodiesel, actually keffiyeh thundercats photo booth pour-over twee fam food truck microdosing banh mi. Vice activated charcoal raclette unicorn live-edge post-ironic. Heirloom vexillologist coloring book, beard deep v letterpress echo park humblebrag tilde. + +90's four loko seitan photo booth gochujang freegan tumeric listicle fam ugh humblebrag. Bespoke leggings gastropub, biodiesel brunch pug fashion axe meh swag art party neutra deep v chia. Enamel pin fanny pack knausgaard tofu, artisan cronut hammock meditation occupy master cleanse chartreuse lumbersexual. Kombucha kogi viral truffaut synth distillery single-origin coffee ugh slow-carb marfa selfies. Pitchfork schlitz semiotics fanny pack, ugh artisan vegan vaporware hexagon. Polaroid fixie post-ironic venmo wolf ramps **kale chips**. + +> There should be no margin above this first sentence. +> +> Blockquotes should be a lighter gray with a border along the left side in the secondary color. +> +> There should be no margin below this final sentence. + +## First Header 2 + +This is a normal paragraph following a header. Knausgaard kale chips snackwave microdosing cronut copper mug swag synth bitters letterpress glossier **craft beer**. Mumblecore bushwick authentic gochujang vegan chambray meditation jean shorts irony. Viral farm-to-table kale chips, pork belly palo santo distillery activated charcoal aesthetic jianbing air plant woke lomo VHS organic. Tattooed locavore succulents heirloom, small batch sriracha echo park DIY af. Shaman you probably haven't heard of them copper mug, crucifix green juice vape *single-origin coffee* brunch actually. Mustache etsy vexillologist raclette authentic fam. Tousled beard humblebrag asymmetrical. I love turkey, I love my job, I love my friends, I love Chardonnay! + +Deae legum paulatimque terra, non vos mutata tacet: dic. Vocant docuique me plumas fila quin afuerunt copia haec o neque. + +On big screens, paragraphs and headings should not take up the full container width, but we want tables, code blocks and similar to take the full width. + +Scenester tumeric pickled, authentic crucifix post-ironic fam freegan VHS pork belly 8-bit yuccie PBR&B. **I love this life we live in**. + + +## Second Header 2 + +> This is a blockquote following a header. Bacon ipsum dolor sit amet t-bone doner shank drumstick, pork belly porchetta chuck sausage brisket ham hock rump pig. Chuck kielbasa leberkas, pork bresaola ham hock filet mignon cow shoulder short ribs biltong. + +### Header 3 + +``` +This is a code block following a header. +``` + +Next level leggings before they sold out, PBR&B church-key shaman echo park. Kale chips occupy godard whatever pop-up freegan pork belly selfies. Gastropub Belinda subway tile woke post-ironic seitan. Shabby chic man bun semiotics vape, chia messenger bag plaid cardigan. + +#### Header 4 + +* This is an unordered list following a header. +* This is an unordered list following a header. +* This is an unordered list following a header. + +##### Header 5 + +1. This is an ordered list following a header. +2. This is an ordered list following a header. +3. This is an ordered list following a header. + +###### Header 6 + +| What | Follows | +|-----------|-----------------| +| A table | A header | +| A table | A header | +| A table | A header | + +---------------- + +There's a horizontal rule above and below this. + +---------------- + +Here is an unordered list: + +* Liverpool F.C. +* Chelsea F.C. +* Manchester United F.C. + +And an ordered list: + +1. Michael Brecker +2. Seamus Blake +3. Branford Marsalis + +And an unordered task list: + +- [x] Create a Hugo theme +- [x] Add task lists to it +- [ ] Take a vacation + +And a "mixed" task list: + +- [ ] Pack bags +- ? +- [ ] Travel! + +And a nested list: + +* Jackson 5 + * Michael + * Tito + * Jackie + * Marlon + * Jermaine +* TMNT + * Leonardo + * Michelangelo + * Donatello + * Raphael + +Definition lists can be used with Markdown syntax. Definition headers are bold. + +Name +: Godzilla + +Born +: 1952 + +Birthplace +: Japan + +Color +: Green + + +---------------- + +Tables should have bold headings and alternating shaded rows. + +| Artist | Album | Year | +|-------------------|-----------------|------| +| Michael Jackson | Thriller | 1982 | +| Prince | Purple Rain | 1984 | +| Beastie Boys | License to Ill | 1986 | + +If a table is too wide, it should scroll horizontally. + +| Artist | Album | Year | Label | Awards | Songs | +|-------------------|-----------------|------|-------------|----------|-----------| +| Michael Jackson | Thriller | 1982 | Epic Records | Grammy Award for Album of the Year, American Music Award for Favorite Pop/Rock Album, American Music Award for Favorite Soul/R&B Album, Brit Award for Best Selling Album, Grammy Award for Best Engineered Album, Non-Classical | Wanna Be Startin' Somethin', Baby Be Mine, The Girl Is Mine, Thriller, Beat It, Billie Jean, Human Nature, P.Y.T. (Pretty Young Thing), The Lady in My Life | +| Prince | Purple Rain | 1984 | Warner Brothers Records | Grammy Award for Best Score Soundtrack for Visual Media, American Music Award for Favorite Pop/Rock Album, American Music Award for Favorite Soul/R&B Album, Brit Award for Best Soundtrack/Cast Recording, Grammy Award for Best Rock Performance by a Duo or Group with Vocal | Let's Go Crazy, Take Me With U, The Beautiful Ones, Computer Blue, Darling Nikki, When Doves Cry, I Would Die 4 U, Baby I'm a Star, Purple Rain | +| Beastie Boys | License to Ill | 1986 | Mercury Records | noawardsbutthistablecelliswide | Rhymin & Stealin, The New Style, She's Crafty, Posse in Effect, Slow Ride, Girls, (You Gotta) Fight for Your Right, No Sleep Till Brooklyn, Paul Revere, Hold It Now, Hit It, Brass Monkey, Slow and Low, Time to Get Ill | + +---------------- + +Code snippets like `var foo = "bar";` can be shown inline. + +Also, `this should vertically align` ~~`with this`~~ ~~and this~~. + +Code can also be shown in a block element. + +``` +foo := "bar"; +bar := "foo"; +``` + +Code can also use syntax highlighting. + +```go +func main() { + input := `var foo = "bar";` + + lexer := lexers.Get("javascript") + iterator, _ := lexer.Tokenise(nil, input) + style := styles.Get("github") + formatter := html.New(html.WithLineNumbers()) + + var buff bytes.Buffer + formatter.Format(&buff, style, iterator) + + fmt.Println(buff.String()) +} +``` + +``` +Long, single-line code blocks should not wrap. They should horizontally scroll if they are too long. This line should be long enough to demonstrate this. +``` + +Inline code inside table cells should still be distinguishable. + +| Language | Code | +|-------------|--------------------| +| Javascript | `var foo = "bar";` | +| Ruby | `foo = "bar"{` | + +---------------- + +Small images should be shown at their actual size. + +![](https://upload.wikimedia.org/wikipedia/commons/thumb/9/9e/Picea_abies_shoot_with_buds%2C_Sogndal%2C_Norway.jpg/240px-Picea_abies_shoot_with_buds%2C_Sogndal%2C_Norway.jpg) + +Large images should always scale down and fit in the content container. + +![](https://upload.wikimedia.org/wikipedia/commons/thumb/9/9e/Picea_abies_shoot_with_buds%2C_Sogndal%2C_Norway.jpg/1024px-Picea_abies_shoot_with_buds%2C_Sogndal%2C_Norway.jpg) + +_The photo above of the Spruce Picea abies shoot with foliage buds: Bjørn Erik Pedersen, CC-BY-SA._ + + +## Components + +### Alerts + +{{< alert >}}This is an alert.{{< /alert >}} +{{< alert title="Note" >}}This is an alert with a title.{{< /alert >}} +{{% alert title="Note" %}}This is an alert with a title and **Markdown**.{{% /alert %}} +{{< alert color="success" >}}This is a successful alert.{{< /alert >}} +{{< alert color="warning" >}}This is a warning.{{< /alert >}} +{{< alert color="warning" title="Warning" >}}This is a warning with a title.{{< /alert >}} + + +## Another Heading + +Add some sections here to see how the ToC looks like. Bacon ipsum dolor sit amet t-bone doner shank drumstick, pork belly porchetta chuck sausage brisket ham hock rump pig. Chuck kielbasa leberkas, pork bresaola ham hock filet mignon cow shoulder short ribs biltong. + +### This Document + +Inguina genus: Anaphen post: lingua violente voce suae meus aetate diversi. Orbis unam nec flammaeque status deam Silenum erat et a ferrea. Excitus rigidum ait: vestro et Herculis convicia: nitidae deseruit coniuge Proteaque adiciam *eripitur*? Sitim noceat signa *probat quidem*. Sua longis *fugatis* quidem genae. + + +### Pixel Count + +Tilde photo booth wayfarers cliche lomo intelligentsia man braid kombucha vaporware farm-to-table mixtape portland. PBR&B pickled cornhole ugh try-hard ethical subway tile. Fixie paleo intelligentsia pabst. Ennui waistcoat vinyl gochujang. Poutine salvia authentic affogato, chambray lumbersexual shabby chic. + +### Contact Info + +Plaid hell of cred microdosing, succulents tilde pour-over. Offal shabby chic 3 wolf moon blue bottle raw denim normcore poutine pork belly. + + +### External Links + +Stumptown PBR&B keytar plaid street art, forage XOXO pitchfork selvage affogato green juice listicle pickled everyday carry hashtag. Organic sustainable letterpress sartorial scenester intelligentsia swag bushwick. Put a bird on it stumptown neutra locavore. IPhone typewriter messenger bag narwhal. Ennui cold-pressed seitan flannel keytar, single-origin coffee adaptogen occupy yuccie williamsburg chillwave shoreditch forage waistcoat. + + + +``` +This is the final element on the page and there should be no margin below this. +``` diff --git a/doc-site/content/en/docs2/Tasks/Ponycopters/launching-ponycopters.md b/doc-site/content/en/docs2/Tasks/Ponycopters/launching-ponycopters.md new file mode 100644 index 0000000..54a857a --- /dev/null +++ b/doc-site/content/en/docs2/Tasks/Ponycopters/launching-ponycopters.md @@ -0,0 +1,239 @@ +--- +title: "Launching Ponycopters" +linkTitle: "Launching Ponycopters" +date: 2017-01-05 +weight: 3 +description: > + A short lead description about this content page. It can be **bold** or _italic_ and can be split over multiple paragraphs. +--- + +{{% pageinfo %}} +This is a placeholder page. Replace it with your own content. +{{% /pageinfo %}} + +Text can be **bold**, _italic_, or ~~strikethrough~~. [Links](https://gohugo.io) should be blue with no underlines (unless hovered over). + +There should be whitespace between paragraphs. Vape migas chillwave sriracha poutine try-hard distillery. Tattooed shabby chic small batch, pabst art party heirloom letterpress air plant pop-up. Sustainable chia skateboard art party banjo cardigan normcore affogato vexillologist quinoa meggings man bun master cleanse shoreditch readymade. Yuccie prism four dollar toast tbh cardigan iPhone, tumblr listicle live-edge VHS. Pug lyft normcore hot chicken biodiesel, actually keffiyeh thundercats photo booth pour-over twee fam food truck microdosing banh mi. Vice activated charcoal raclette unicorn live-edge post-ironic. Heirloom vexillologist coloring book, beard deep v letterpress echo park humblebrag tilde. + +90's four loko seitan photo booth gochujang freegan tumeric listicle fam ugh humblebrag. Bespoke leggings gastropub, biodiesel brunch pug fashion axe meh swag art party neutra deep v chia. Enamel pin fanny pack knausgaard tofu, artisan cronut hammock meditation occupy master cleanse chartreuse lumbersexual. Kombucha kogi viral truffaut synth distillery single-origin coffee ugh slow-carb marfa selfies. Pitchfork schlitz semiotics fanny pack, ugh artisan vegan vaporware hexagon. Polaroid fixie post-ironic venmo wolf ramps **kale chips**. + +> There should be no margin above this first sentence. +> +> Blockquotes should be a lighter gray with a border along the left side in the secondary color. +> +> There should be no margin below this final sentence. + +## First Header 2 + +This is a normal paragraph following a header. Knausgaard kale chips snackwave microdosing cronut copper mug swag synth bitters letterpress glossier **craft beer**. Mumblecore bushwick authentic gochujang vegan chambray meditation jean shorts irony. Viral farm-to-table kale chips, pork belly palo santo distillery activated charcoal aesthetic jianbing air plant woke lomo VHS organic. Tattooed locavore succulents heirloom, small batch sriracha echo park DIY af. Shaman you probably haven't heard of them copper mug, crucifix green juice vape *single-origin coffee* brunch actually. Mustache etsy vexillologist raclette authentic fam. Tousled beard humblebrag asymmetrical. I love turkey, I love my job, I love my friends, I love Chardonnay! + +Deae legum paulatimque terra, non vos mutata tacet: dic. Vocant docuique me plumas fila quin afuerunt copia haec o neque. + +On big screens, paragraphs and headings should not take up the full container width, but we want tables, code blocks and similar to take the full width. + +Scenester tumeric pickled, authentic crucifix post-ironic fam freegan VHS pork belly 8-bit yuccie PBR&B. **I love this life we live in**. + + +## Second Header 2 + +> This is a blockquote following a header. Bacon ipsum dolor sit amet t-bone doner shank drumstick, pork belly porchetta chuck sausage brisket ham hock rump pig. Chuck kielbasa leberkas, pork bresaola ham hock filet mignon cow shoulder short ribs biltong. + +### Header 3 + +``` +This is a code block following a header. +``` + +Next level leggings before they sold out, PBR&B church-key shaman echo park. Kale chips occupy godard whatever pop-up freegan pork belly selfies. Gastropub Belinda subway tile woke post-ironic seitan. Shabby chic man bun semiotics vape, chia messenger bag plaid cardigan. + +#### Header 4 + +* This is an unordered list following a header. +* This is an unordered list following a header. +* This is an unordered list following a header. + +##### Header 5 + +1. This is an ordered list following a header. +2. This is an ordered list following a header. +3. This is an ordered list following a header. + +###### Header 6 + +| What | Follows | +|-----------|-----------------| +| A table | A header | +| A table | A header | +| A table | A header | + +---------------- + +There's a horizontal rule above and below this. + +---------------- + +Here is an unordered list: + +* Liverpool F.C. +* Chelsea F.C. +* Manchester United F.C. + +And an ordered list: + +1. Michael Brecker +2. Seamus Blake +3. Branford Marsalis + +And an unordered task list: + +- [x] Create a Hugo theme +- [x] Add task lists to it +- [ ] Take a vacation + +And a "mixed" task list: + +- [ ] Pack bags +- ? +- [ ] Travel! + +And a nested list: + +* Jackson 5 + * Michael + * Tito + * Jackie + * Marlon + * Jermaine +* TMNT + * Leonardo + * Michelangelo + * Donatello + * Raphael + +Definition lists can be used with Markdown syntax. Definition headers are bold. + +Name +: Godzilla + +Born +: 1952 + +Birthplace +: Japan + +Color +: Green + + +---------------- + +Tables should have bold headings and alternating shaded rows. + +| Artist | Album | Year | +|-------------------|-----------------|------| +| Michael Jackson | Thriller | 1982 | +| Prince | Purple Rain | 1984 | +| Beastie Boys | License to Ill | 1986 | + +If a table is too wide, it should scroll horizontally. + +| Artist | Album | Year | Label | Awards | Songs | +|-------------------|-----------------|------|-------------|----------|-----------| +| Michael Jackson | Thriller | 1982 | Epic Records | Grammy Award for Album of the Year, American Music Award for Favorite Pop/Rock Album, American Music Award for Favorite Soul/R&B Album, Brit Award for Best Selling Album, Grammy Award for Best Engineered Album, Non-Classical | Wanna Be Startin' Somethin', Baby Be Mine, The Girl Is Mine, Thriller, Beat It, Billie Jean, Human Nature, P.Y.T. (Pretty Young Thing), The Lady in My Life | +| Prince | Purple Rain | 1984 | Warner Brothers Records | Grammy Award for Best Score Soundtrack for Visual Media, American Music Award for Favorite Pop/Rock Album, American Music Award for Favorite Soul/R&B Album, Brit Award for Best Soundtrack/Cast Recording, Grammy Award for Best Rock Performance by a Duo or Group with Vocal | Let's Go Crazy, Take Me With U, The Beautiful Ones, Computer Blue, Darling Nikki, When Doves Cry, I Would Die 4 U, Baby I'm a Star, Purple Rain | +| Beastie Boys | License to Ill | 1986 | Mercury Records | noawardsbutthistablecelliswide | Rhymin & Stealin, The New Style, She's Crafty, Posse in Effect, Slow Ride, Girls, (You Gotta) Fight for Your Right, No Sleep Till Brooklyn, Paul Revere, Hold It Now, Hit It, Brass Monkey, Slow and Low, Time to Get Ill | + +---------------- + +Code snippets like `var foo = "bar";` can be shown inline. + +Also, `this should vertically align` ~~`with this`~~ ~~and this~~. + +Code can also be shown in a block element. + +``` +foo := "bar"; +bar := "foo"; +``` + +Code can also use syntax highlighting. + +```go +func main() { + input := `var foo = "bar";` + + lexer := lexers.Get("javascript") + iterator, _ := lexer.Tokenise(nil, input) + style := styles.Get("github") + formatter := html.New(html.WithLineNumbers()) + + var buff bytes.Buffer + formatter.Format(&buff, style, iterator) + + fmt.Println(buff.String()) +} +``` + +``` +Long, single-line code blocks should not wrap. They should horizontally scroll if they are too long. This line should be long enough to demonstrate this. +``` + +Inline code inside table cells should still be distinguishable. + +| Language | Code | +|-------------|--------------------| +| Javascript | `var foo = "bar";` | +| Ruby | `foo = "bar"{` | + +---------------- + +Small images should be shown at their actual size. + +![](https://upload.wikimedia.org/wikipedia/commons/thumb/9/9e/Picea_abies_shoot_with_buds%2C_Sogndal%2C_Norway.jpg/240px-Picea_abies_shoot_with_buds%2C_Sogndal%2C_Norway.jpg) + +Large images should always scale down and fit in the content container. + +![](https://upload.wikimedia.org/wikipedia/commons/thumb/9/9e/Picea_abies_shoot_with_buds%2C_Sogndal%2C_Norway.jpg/1024px-Picea_abies_shoot_with_buds%2C_Sogndal%2C_Norway.jpg) + +_The photo above of the Spruce Picea abies shoot with foliage buds: Bjørn Erik Pedersen, CC-BY-SA._ + + +## Components + +### Alerts + +{{< alert >}}This is an alert.{{< /alert >}} +{{< alert title="Note" >}}This is an alert with a title.{{< /alert >}} +{{% alert title="Note" %}}This is an alert with a title and **Markdown**.{{% /alert %}} +{{< alert color="success" >}}This is a successful alert.{{< /alert >}} +{{< alert color="warning" >}}This is a warning.{{< /alert >}} +{{< alert color="warning" title="Warning" >}}This is a warning with a title.{{< /alert >}} + + +## Another Heading + +Add some sections here to see how the ToC looks like. Bacon ipsum dolor sit amet t-bone doner shank drumstick, pork belly porchetta chuck sausage brisket ham hock rump pig. Chuck kielbasa leberkas, pork bresaola ham hock filet mignon cow shoulder short ribs biltong. + +### This Document + +Inguina genus: Anaphen post: lingua violente voce suae meus aetate diversi. Orbis unam nec flammaeque status deam Silenum erat et a ferrea. Excitus rigidum ait: vestro et Herculis convicia: nitidae deseruit coniuge Proteaque adiciam *eripitur*? Sitim noceat signa *probat quidem*. Sua longis *fugatis* quidem genae. + + +### Pixel Count + +Tilde photo booth wayfarers cliche lomo intelligentsia man braid kombucha vaporware farm-to-table mixtape portland. PBR&B pickled cornhole ugh try-hard ethical subway tile. Fixie paleo intelligentsia pabst. Ennui waistcoat vinyl gochujang. Poutine salvia authentic affogato, chambray lumbersexual shabby chic. + +### Contact Info + +Plaid hell of cred microdosing, succulents tilde pour-over. Offal shabby chic 3 wolf moon blue bottle raw denim normcore poutine pork belly. + + +### External Links + +Stumptown PBR&B keytar plaid street art, forage XOXO pitchfork selvage affogato green juice listicle pickled everyday carry hashtag. Organic sustainable letterpress sartorial scenester intelligentsia swag bushwick. Put a bird on it stumptown neutra locavore. IPhone typewriter messenger bag narwhal. Ennui cold-pressed seitan flannel keytar, single-origin coffee adaptogen occupy yuccie williamsburg chillwave shoreditch forage waistcoat. + + + +``` +This is the final element on the page and there should be no margin below this. +``` diff --git a/doc-site/content/en/docs2/Tasks/_index.md b/doc-site/content/en/docs2/Tasks/_index.md new file mode 100755 index 0000000..e43ab7c --- /dev/null +++ b/doc-site/content/en/docs2/Tasks/_index.md @@ -0,0 +1,25 @@ + +--- +title: "Core Tasks" +linkTitle: "Core Tasks" +weight: 6 +date: 2017-01-05 +description: > + What can your user do with your project? +--- + +{{% pageinfo %}} +This is a placeholder page that shows you how to use this template site. +{{% /pageinfo %}} + +Think about your project’s features and use cases. Use these to choose your core tasks. Each granular use case (enable x, configure y) should have a corresponding tasks page or tasks page section. Users should be able to quickly refer to your core tasks when they need to find out how to do one specific thing, rather than having to look for the instructions in a bigger tutorial or example. Think of your tasks pages as a cookbook with different procedures your users can combine to create something more substantial. + +You can give each task a page, or you can group related tasks together in a page, such as tasks related to a particular feature. As well as grouping related tasks in single pages, you can also group task pages in nested folders with an index page as an overview, as seen in this example site. Or if you have a small docset like the [Docsy User Guide](https://docsy.dev/docs/) with no Tutorials or Concepts pages, consider adding your feature-specific pages at the top level of your docs rather than in a Tasks section. + +Each task should give the user + +* The prerequisites for this task, if any (this can be specified at the top of a multi-task page if they're the same for all the page's tasks. "All these tasks assume that you understand....and that you have already...."). +* What this task accomplishes. +* Instructions for the task. If it involves editing a file, running a command, or writing code, provide code-formatted example snippets to show the user what to do! If there are multiple steps, provide them as a numbered list. +* If appropriate, links to related concept, tutorial, or example pages. + diff --git a/doc-site/content/en/docs2/Tasks/beds.md b/doc-site/content/en/docs2/Tasks/beds.md new file mode 100644 index 0000000..4c5803d --- /dev/null +++ b/doc-site/content/en/docs2/Tasks/beds.md @@ -0,0 +1,239 @@ +--- +title: "Bed and Chair Metrics" +date: 2017-01-05 +weight: 2 +description: > + A short lead description about this content page. It can be **bold** or _italic_ and can be split over multiple paragraphs. +--- + +{{% pageinfo %}} +This is a placeholder page. Replace it with your own content. +{{% /pageinfo %}} + + +Text can be **bold**, _italic_, or ~~strikethrough~~. [Links](https://gohugo.io) should be blue with no underlines (unless hovered over). + +There should be whitespace between paragraphs. Vape migas chillwave sriracha poutine try-hard distillery. Tattooed shabby chic small batch, pabst art party heirloom letterpress air plant pop-up. Sustainable chia skateboard art party banjo cardigan normcore affogato vexillologist quinoa meggings man bun master cleanse shoreditch readymade. Yuccie prism four dollar toast tbh cardigan iPhone, tumblr listicle live-edge VHS. Pug lyft normcore hot chicken biodiesel, actually keffiyeh thundercats photo booth pour-over twee fam food truck microdosing banh mi. Vice activated charcoal raclette unicorn live-edge post-ironic. Heirloom vexillologist coloring book, beard deep v letterpress echo park humblebrag tilde. + +90's four loko seitan photo booth gochujang freegan tumeric listicle fam ugh humblebrag. Bespoke leggings gastropub, biodiesel brunch pug fashion axe meh swag art party neutra deep v chia. Enamel pin fanny pack knausgaard tofu, artisan cronut hammock meditation occupy master cleanse chartreuse lumbersexual. Kombucha kogi viral truffaut synth distillery single-origin coffee ugh slow-carb marfa selfies. Pitchfork schlitz semiotics fanny pack, ugh artisan vegan vaporware hexagon. Polaroid fixie post-ironic venmo wolf ramps **kale chips**. + +> There should be no margin above this first sentence. +> +> Blockquotes should be a lighter gray with a border along the left side in the secondary color. +> +> There should be no margin below this final sentence. + +## First Header 2 + +This is a normal paragraph following a header. Knausgaard kale chips snackwave microdosing cronut copper mug swag synth bitters letterpress glossier **craft beer**. Mumblecore bushwick authentic gochujang vegan chambray meditation jean shorts irony. Viral farm-to-table kale chips, pork belly palo santo distillery activated charcoal aesthetic jianbing air plant woke lomo VHS organic. Tattooed locavore succulents heirloom, small batch sriracha echo park DIY af. Shaman you probably haven't heard of them copper mug, crucifix green juice vape *single-origin coffee* brunch actually. Mustache etsy vexillologist raclette authentic fam. Tousled beard humblebrag asymmetrical. I love turkey, I love my job, I love my friends, I love Chardonnay! + +Deae legum paulatimque terra, non vos mutata tacet: dic. Vocant docuique me plumas fila quin afuerunt copia haec o neque. + +On big screens, paragraphs and headings should not take up the full container width, but we want tables, code blocks and similar to take the full width. + +Scenester tumeric pickled, authentic crucifix post-ironic fam freegan VHS pork belly 8-bit yuccie PBR&B. **I love this life we live in**. + + +## Second Header 2 + +> This is a blockquote following a header. Bacon ipsum dolor sit amet t-bone doner shank drumstick, pork belly porchetta chuck sausage brisket ham hock rump pig. Chuck kielbasa leberkas, pork bresaola ham hock filet mignon cow shoulder short ribs biltong. + +### Header 3 + +``` +This is a code block following a header. +``` + +Next level leggings before they sold out, PBR&B church-key shaman echo park. Kale chips occupy godard whatever pop-up freegan pork belly selfies. Gastropub Belinda subway tile woke post-ironic seitan. Shabby chic man bun semiotics vape, chia messenger bag plaid cardigan. + +#### Header 4 + +* This is an unordered list following a header. +* This is an unordered list following a header. +* This is an unordered list following a header. + +##### Header 5 + +1. This is an ordered list following a header. +2. This is an ordered list following a header. +3. This is an ordered list following a header. + +###### Header 6 + +| What | Follows | +|-----------|-----------------| +| A table | A header | +| A table | A header | +| A table | A header | + +---------------- + +There's a horizontal rule above and below this. + +---------------- + +Here is an unordered list: + +* Liverpool F.C. +* Chelsea F.C. +* Manchester United F.C. + +And an ordered list: + +1. Michael Brecker +2. Seamus Blake +3. Branford Marsalis + +And an unordered task list: + +- [x] Create a Hugo theme +- [x] Add task lists to it +- [ ] Take a vacation + +And a "mixed" task list: + +- [ ] Pack bags +- ? +- [ ] Travel! + +And a nested list: + +* Jackson 5 + * Michael + * Tito + * Jackie + * Marlon + * Jermaine +* TMNT + * Leonardo + * Michelangelo + * Donatello + * Raphael + +Definition lists can be used with Markdown syntax. Definition headers are bold. + +Name +: Godzilla + +Born +: 1952 + +Birthplace +: Japan + +Color +: Green + + +---------------- + +Tables should have bold headings and alternating shaded rows. + +| Artist | Album | Year | +|-------------------|-----------------|------| +| Michael Jackson | Thriller | 1982 | +| Prince | Purple Rain | 1984 | +| Beastie Boys | License to Ill | 1986 | + +If a table is too wide, it should scroll horizontally. + +| Artist | Album | Year | Label | Awards | Songs | +|-------------------|-----------------|------|-------------|----------|-----------| +| Michael Jackson | Thriller | 1982 | Epic Records | Grammy Award for Album of the Year, American Music Award for Favorite Pop/Rock Album, American Music Award for Favorite Soul/R&B Album, Brit Award for Best Selling Album, Grammy Award for Best Engineered Album, Non-Classical | Wanna Be Startin' Somethin', Baby Be Mine, The Girl Is Mine, Thriller, Beat It, Billie Jean, Human Nature, P.Y.T. (Pretty Young Thing), The Lady in My Life | +| Prince | Purple Rain | 1984 | Warner Brothers Records | Grammy Award for Best Score Soundtrack for Visual Media, American Music Award for Favorite Pop/Rock Album, American Music Award for Favorite Soul/R&B Album, Brit Award for Best Soundtrack/Cast Recording, Grammy Award for Best Rock Performance by a Duo or Group with Vocal | Let's Go Crazy, Take Me With U, The Beautiful Ones, Computer Blue, Darling Nikki, When Doves Cry, I Would Die 4 U, Baby I'm a Star, Purple Rain | +| Beastie Boys | License to Ill | 1986 | Mercury Records | noawardsbutthistablecelliswide | Rhymin & Stealin, The New Style, She's Crafty, Posse in Effect, Slow Ride, Girls, (You Gotta) Fight for Your Right, No Sleep Till Brooklyn, Paul Revere, Hold It Now, Hit It, Brass Monkey, Slow and Low, Time to Get Ill | + +---------------- + +Code snippets like `var foo = "bar";` can be shown inline. + +Also, `this should vertically align` ~~`with this`~~ ~~and this~~. + +Code can also be shown in a block element. + +``` +foo := "bar"; +bar := "foo"; +``` + +Code can also use syntax highlighting. + +```go +func main() { + input := `var foo = "bar";` + + lexer := lexers.Get("javascript") + iterator, _ := lexer.Tokenise(nil, input) + style := styles.Get("github") + formatter := html.New(html.WithLineNumbers()) + + var buff bytes.Buffer + formatter.Format(&buff, style, iterator) + + fmt.Println(buff.String()) +} +``` + +``` +Long, single-line code blocks should not wrap. They should horizontally scroll if they are too long. This line should be long enough to demonstrate this. +``` + +Inline code inside table cells should still be distinguishable. + +| Language | Code | +|-------------|--------------------| +| Javascript | `var foo = "bar";` | +| Ruby | `foo = "bar"{` | + +---------------- + +Small images should be shown at their actual size. + +![](https://upload.wikimedia.org/wikipedia/commons/thumb/9/9e/Picea_abies_shoot_with_buds%2C_Sogndal%2C_Norway.jpg/240px-Picea_abies_shoot_with_buds%2C_Sogndal%2C_Norway.jpg) + +Large images should always scale down and fit in the content container. + +![](https://upload.wikimedia.org/wikipedia/commons/thumb/9/9e/Picea_abies_shoot_with_buds%2C_Sogndal%2C_Norway.jpg/1024px-Picea_abies_shoot_with_buds%2C_Sogndal%2C_Norway.jpg) + +_The photo above of the Spruce Picea abies shoot with foliage buds: Bjørn Erik Pedersen, CC-BY-SA._ + + +## Components + +### Alerts + +{{< alert >}}This is an alert.{{< /alert >}} +{{< alert title="Note" >}}This is an alert with a title.{{< /alert >}} +{{% alert title="Note" %}}This is an alert with a title and **Markdown**.{{% /alert %}} +{{< alert color="success" >}}This is a successful alert.{{< /alert >}} +{{< alert color="warning" >}}This is a warning.{{< /alert >}} +{{< alert color="warning" title="Warning" >}}This is a warning with a title.{{< /alert >}} + + +## Another Heading + +Add some sections here to see how the ToC looks like. Bacon ipsum dolor sit amet t-bone doner shank drumstick, pork belly porchetta chuck sausage brisket ham hock rump pig. Chuck kielbasa leberkas, pork bresaola ham hock filet mignon cow shoulder short ribs biltong. + +### This Document + +Inguina genus: Anaphen post: lingua violente voce suae meus aetate diversi. Orbis unam nec flammaeque status deam Silenum erat et a ferrea. Excitus rigidum ait: vestro et Herculis convicia: nitidae deseruit coniuge Proteaque adiciam *eripitur*? Sitim noceat signa *probat quidem*. Sua longis *fugatis* quidem genae. + + +### Pixel Count + +Tilde photo booth wayfarers cliche lomo intelligentsia man braid kombucha vaporware farm-to-table mixtape portland. PBR&B pickled cornhole ugh try-hard ethical subway tile. Fixie paleo intelligentsia pabst. Ennui waistcoat vinyl gochujang. Poutine salvia authentic affogato, chambray lumbersexual shabby chic. + +### Contact Info + +Plaid hell of cred microdosing, succulents tilde pour-over. Offal shabby chic 3 wolf moon blue bottle raw denim normcore poutine pork belly. + + +### External Links + +Stumptown PBR&B keytar plaid street art, forage XOXO pitchfork selvage affogato green juice listicle pickled everyday carry hashtag. Organic sustainable letterpress sartorial scenester intelligentsia swag bushwick. Put a bird on it stumptown neutra locavore. IPhone typewriter messenger bag narwhal. Ennui cold-pressed seitan flannel keytar, single-origin coffee adaptogen occupy yuccie williamsburg chillwave shoreditch forage waistcoat. + + + +``` +This is the final element on the page and there should be no margin below this. +``` diff --git a/doc-site/content/en/docs2/Tasks/porridge.md b/doc-site/content/en/docs2/Tasks/porridge.md new file mode 100644 index 0000000..71ef273 --- /dev/null +++ b/doc-site/content/en/docs2/Tasks/porridge.md @@ -0,0 +1,239 @@ +--- +title: "Porridge Assessment" +date: 2017-01-05 +weight: 4 +description: > + A short lead description about this content page. It can be **bold** or _italic_ and can be split over multiple paragraphs. +--- + +{{% pageinfo %}} +This is a placeholder page. Replace it with your own content. +{{% /pageinfo %}} + + +Text can be **bold**, _italic_, or ~~strikethrough~~. [Links](https://gohugo.io) should be blue with no underlines (unless hovered over). + +There should be whitespace between paragraphs. Vape migas chillwave sriracha poutine try-hard distillery. Tattooed shabby chic small batch, pabst art party heirloom letterpress air plant pop-up. Sustainable chia skateboard art party banjo cardigan normcore affogato vexillologist quinoa meggings man bun master cleanse shoreditch readymade. Yuccie prism four dollar toast tbh cardigan iPhone, tumblr listicle live-edge VHS. Pug lyft normcore hot chicken biodiesel, actually keffiyeh thundercats photo booth pour-over twee fam food truck microdosing banh mi. Vice activated charcoal raclette unicorn live-edge post-ironic. Heirloom vexillologist coloring book, beard deep v letterpress echo park humblebrag tilde. + +90's four loko seitan photo booth gochujang freegan tumeric listicle fam ugh humblebrag. Bespoke leggings gastropub, biodiesel brunch pug fashion axe meh swag art party neutra deep v chia. Enamel pin fanny pack knausgaard tofu, artisan cronut hammock meditation occupy master cleanse chartreuse lumbersexual. Kombucha kogi viral truffaut synth distillery single-origin coffee ugh slow-carb marfa selfies. Pitchfork schlitz semiotics fanny pack, ugh artisan vegan vaporware hexagon. Polaroid fixie post-ironic venmo wolf ramps **kale chips**. + +> There should be no margin above this first sentence. +> +> Blockquotes should be a lighter gray with a border along the left side in the secondary color. +> +> There should be no margin below this final sentence. + +## First Header 2 + +This is a normal paragraph following a header. Knausgaard kale chips snackwave microdosing cronut copper mug swag synth bitters letterpress glossier **craft beer**. Mumblecore bushwick authentic gochujang vegan chambray meditation jean shorts irony. Viral farm-to-table kale chips, pork belly palo santo distillery activated charcoal aesthetic jianbing air plant woke lomo VHS organic. Tattooed locavore succulents heirloom, small batch sriracha echo park DIY af. Shaman you probably haven't heard of them copper mug, crucifix green juice vape *single-origin coffee* brunch actually. Mustache etsy vexillologist raclette authentic fam. Tousled beard humblebrag asymmetrical. I love turkey, I love my job, I love my friends, I love Chardonnay! + +Deae legum paulatimque terra, non vos mutata tacet: dic. Vocant docuique me plumas fila quin afuerunt copia haec o neque. + +On big screens, paragraphs and headings should not take up the full container width, but we want tables, code blocks and similar to take the full width. + +Scenester tumeric pickled, authentic crucifix post-ironic fam freegan VHS pork belly 8-bit yuccie PBR&B. **I love this life we live in**. + + +## Second Header 2 + +> This is a blockquote following a header. Bacon ipsum dolor sit amet t-bone doner shank drumstick, pork belly porchetta chuck sausage brisket ham hock rump pig. Chuck kielbasa leberkas, pork bresaola ham hock filet mignon cow shoulder short ribs biltong. + +### Header 3 + +``` +This is a code block following a header. +``` + +Next level leggings before they sold out, PBR&B church-key shaman echo park. Kale chips occupy godard whatever pop-up freegan pork belly selfies. Gastropub Belinda subway tile woke post-ironic seitan. Shabby chic man bun semiotics vape, chia messenger bag plaid cardigan. + +#### Header 4 + +* This is an unordered list following a header. +* This is an unordered list following a header. +* This is an unordered list following a header. + +##### Header 5 + +1. This is an ordered list following a header. +2. This is an ordered list following a header. +3. This is an ordered list following a header. + +###### Header 6 + +| What | Follows | +|-----------|-----------------| +| A table | A header | +| A table | A header | +| A table | A header | + +---------------- + +There's a horizontal rule above and below this. + +---------------- + +Here is an unordered list: + +* Liverpool F.C. +* Chelsea F.C. +* Manchester United F.C. + +And an ordered list: + +1. Michael Brecker +2. Seamus Blake +3. Branford Marsalis + +And an unordered task list: + +- [x] Create a Hugo theme +- [x] Add task lists to it +- [ ] Take a vacation + +And a "mixed" task list: + +- [ ] Pack bags +- ? +- [ ] Travel! + +And a nested list: + +* Jackson 5 + * Michael + * Tito + * Jackie + * Marlon + * Jermaine +* TMNT + * Leonardo + * Michelangelo + * Donatello + * Raphael + +Definition lists can be used with Markdown syntax. Definition headers are bold. + +Name +: Godzilla + +Born +: 1952 + +Birthplace +: Japan + +Color +: Green + + +---------------- + +Tables should have bold headings and alternating shaded rows. + +| Artist | Album | Year | +|-------------------|-----------------|------| +| Michael Jackson | Thriller | 1982 | +| Prince | Purple Rain | 1984 | +| Beastie Boys | License to Ill | 1986 | + +If a table is too wide, it should scroll horizontally. + +| Artist | Album | Year | Label | Awards | Songs | +|-------------------|-----------------|------|-------------|----------|-----------| +| Michael Jackson | Thriller | 1982 | Epic Records | Grammy Award for Album of the Year, American Music Award for Favorite Pop/Rock Album, American Music Award for Favorite Soul/R&B Album, Brit Award for Best Selling Album, Grammy Award for Best Engineered Album, Non-Classical | Wanna Be Startin' Somethin', Baby Be Mine, The Girl Is Mine, Thriller, Beat It, Billie Jean, Human Nature, P.Y.T. (Pretty Young Thing), The Lady in My Life | +| Prince | Purple Rain | 1984 | Warner Brothers Records | Grammy Award for Best Score Soundtrack for Visual Media, American Music Award for Favorite Pop/Rock Album, American Music Award for Favorite Soul/R&B Album, Brit Award for Best Soundtrack/Cast Recording, Grammy Award for Best Rock Performance by a Duo or Group with Vocal | Let's Go Crazy, Take Me With U, The Beautiful Ones, Computer Blue, Darling Nikki, When Doves Cry, I Would Die 4 U, Baby I'm a Star, Purple Rain | +| Beastie Boys | License to Ill | 1986 | Mercury Records | noawardsbutthistablecelliswide | Rhymin & Stealin, The New Style, She's Crafty, Posse in Effect, Slow Ride, Girls, (You Gotta) Fight for Your Right, No Sleep Till Brooklyn, Paul Revere, Hold It Now, Hit It, Brass Monkey, Slow and Low, Time to Get Ill | + +---------------- + +Code snippets like `var foo = "bar";` can be shown inline. + +Also, `this should vertically align` ~~`with this`~~ ~~and this~~. + +Code can also be shown in a block element. + +``` +foo := "bar"; +bar := "foo"; +``` + +Code can also use syntax highlighting. + +```go +func main() { + input := `var foo = "bar";` + + lexer := lexers.Get("javascript") + iterator, _ := lexer.Tokenise(nil, input) + style := styles.Get("github") + formatter := html.New(html.WithLineNumbers()) + + var buff bytes.Buffer + formatter.Format(&buff, style, iterator) + + fmt.Println(buff.String()) +} +``` + +``` +Long, single-line code blocks should not wrap. They should horizontally scroll if they are too long. This line should be long enough to demonstrate this. +``` + +Inline code inside table cells should still be distinguishable. + +| Language | Code | +|-------------|--------------------| +| Javascript | `var foo = "bar";` | +| Ruby | `foo = "bar"{` | + +---------------- + +Small images should be shown at their actual size. + +![](https://upload.wikimedia.org/wikipedia/commons/thumb/9/9e/Picea_abies_shoot_with_buds%2C_Sogndal%2C_Norway.jpg/240px-Picea_abies_shoot_with_buds%2C_Sogndal%2C_Norway.jpg) + +Large images should always scale down and fit in the content container. + +![](https://upload.wikimedia.org/wikipedia/commons/thumb/9/9e/Picea_abies_shoot_with_buds%2C_Sogndal%2C_Norway.jpg/1024px-Picea_abies_shoot_with_buds%2C_Sogndal%2C_Norway.jpg) + +_The photo above of the Spruce Picea abies shoot with foliage buds: Bjørn Erik Pedersen, CC-BY-SA._ + + +## Components + +### Alerts + +{{< alert >}}This is an alert.{{< /alert >}} +{{< alert title="Note" >}}This is an alert with a title.{{< /alert >}} +{{% alert title="Note" %}}This is an alert with a title and **Markdown**.{{% /alert %}} +{{< alert color="success" >}}This is a successful alert.{{< /alert >}} +{{< alert color="warning" >}}This is a warning.{{< /alert >}} +{{< alert color="warning" title="Warning" >}}This is a warning with a title.{{< /alert >}} + + +## Another Heading + +Add some sections here to see how the ToC looks like. Bacon ipsum dolor sit amet t-bone doner shank drumstick, pork belly porchetta chuck sausage brisket ham hock rump pig. Chuck kielbasa leberkas, pork bresaola ham hock filet mignon cow shoulder short ribs biltong. + +### This Document + +Inguina genus: Anaphen post: lingua violente voce suae meus aetate diversi. Orbis unam nec flammaeque status deam Silenum erat et a ferrea. Excitus rigidum ait: vestro et Herculis convicia: nitidae deseruit coniuge Proteaque adiciam *eripitur*? Sitim noceat signa *probat quidem*. Sua longis *fugatis* quidem genae. + + +### Pixel Count + +Tilde photo booth wayfarers cliche lomo intelligentsia man braid kombucha vaporware farm-to-table mixtape portland. PBR&B pickled cornhole ugh try-hard ethical subway tile. Fixie paleo intelligentsia pabst. Ennui waistcoat vinyl gochujang. Poutine salvia authentic affogato, chambray lumbersexual shabby chic. + +### Contact Info + +Plaid hell of cred microdosing, succulents tilde pour-over. Offal shabby chic 3 wolf moon blue bottle raw denim normcore poutine pork belly. + + +### External Links + +Stumptown PBR&B keytar plaid street art, forage XOXO pitchfork selvage affogato green juice listicle pickled everyday carry hashtag. Organic sustainable letterpress sartorial scenester intelligentsia swag bushwick. Put a bird on it stumptown neutra locavore. IPhone typewriter messenger bag narwhal. Ennui cold-pressed seitan flannel keytar, single-origin coffee adaptogen occupy yuccie williamsburg chillwave shoreditch forage waistcoat. + + + +``` +This is the final element on the page and there should be no margin below this. +``` diff --git a/doc-site/content/en/docs2/Tasks/task.md b/doc-site/content/en/docs2/Tasks/task.md new file mode 100644 index 0000000..65b34cd --- /dev/null +++ b/doc-site/content/en/docs2/Tasks/task.md @@ -0,0 +1,239 @@ +--- +title: "Another Task" +date: 2017-01-05 +weight: 5 +description: > + A short lead description about this content page. It can be **bold** or _italic_ and can be split over multiple paragraphs. +--- + +{{% pageinfo %}} +This is a placeholder page. Replace it with your own content. +{{% /pageinfo %}} + + +Text can be **bold**, _italic_, or ~~strikethrough~~. [Links](https://gohugo.io) should be blue with no underlines (unless hovered over). + +There should be whitespace between paragraphs. Vape migas chillwave sriracha poutine try-hard distillery. Tattooed shabby chic small batch, pabst art party heirloom letterpress air plant pop-up. Sustainable chia skateboard art party banjo cardigan normcore affogato vexillologist quinoa meggings man bun master cleanse shoreditch readymade. Yuccie prism four dollar toast tbh cardigan iPhone, tumblr listicle live-edge VHS. Pug lyft normcore hot chicken biodiesel, actually keffiyeh thundercats photo booth pour-over twee fam food truck microdosing banh mi. Vice activated charcoal raclette unicorn live-edge post-ironic. Heirloom vexillologist coloring book, beard deep v letterpress echo park humblebrag tilde. + +90's four loko seitan photo booth gochujang freegan tumeric listicle fam ugh humblebrag. Bespoke leggings gastropub, biodiesel brunch pug fashion axe meh swag art party neutra deep v chia. Enamel pin fanny pack knausgaard tofu, artisan cronut hammock meditation occupy master cleanse chartreuse lumbersexual. Kombucha kogi viral truffaut synth distillery single-origin coffee ugh slow-carb marfa selfies. Pitchfork schlitz semiotics fanny pack, ugh artisan vegan vaporware hexagon. Polaroid fixie post-ironic venmo wolf ramps **kale chips**. + +> There should be no margin above this first sentence. +> +> Blockquotes should be a lighter gray with a border along the left side in the secondary color. +> +> There should be no margin below this final sentence. + +## First Header 2 + +This is a normal paragraph following a header. Knausgaard kale chips snackwave microdosing cronut copper mug swag synth bitters letterpress glossier **craft beer**. Mumblecore bushwick authentic gochujang vegan chambray meditation jean shorts irony. Viral farm-to-table kale chips, pork belly palo santo distillery activated charcoal aesthetic jianbing air plant woke lomo VHS organic. Tattooed locavore succulents heirloom, small batch sriracha echo park DIY af. Shaman you probably haven't heard of them copper mug, crucifix green juice vape *single-origin coffee* brunch actually. Mustache etsy vexillologist raclette authentic fam. Tousled beard humblebrag asymmetrical. I love turkey, I love my job, I love my friends, I love Chardonnay! + +Deae legum paulatimque terra, non vos mutata tacet: dic. Vocant docuique me plumas fila quin afuerunt copia haec o neque. + +On big screens, paragraphs and headings should not take up the full container width, but we want tables, code blocks and similar to take the full width. + +Scenester tumeric pickled, authentic crucifix post-ironic fam freegan VHS pork belly 8-bit yuccie PBR&B. **I love this life we live in**. + + +## Second Header 2 + +> This is a blockquote following a header. Bacon ipsum dolor sit amet t-bone doner shank drumstick, pork belly porchetta chuck sausage brisket ham hock rump pig. Chuck kielbasa leberkas, pork bresaola ham hock filet mignon cow shoulder short ribs biltong. + +### Header 3 + +``` +This is a code block following a header. +``` + +Next level leggings before they sold out, PBR&B church-key shaman echo park. Kale chips occupy godard whatever pop-up freegan pork belly selfies. Gastropub Belinda subway tile woke post-ironic seitan. Shabby chic man bun semiotics vape, chia messenger bag plaid cardigan. + +#### Header 4 + +* This is an unordered list following a header. +* This is an unordered list following a header. +* This is an unordered list following a header. + +##### Header 5 + +1. This is an ordered list following a header. +2. This is an ordered list following a header. +3. This is an ordered list following a header. + +###### Header 6 + +| What | Follows | +|-----------|-----------------| +| A table | A header | +| A table | A header | +| A table | A header | + +---------------- + +There's a horizontal rule above and below this. + +---------------- + +Here is an unordered list: + +* Liverpool F.C. +* Chelsea F.C. +* Manchester United F.C. + +And an ordered list: + +1. Michael Brecker +2. Seamus Blake +3. Branford Marsalis + +And an unordered task list: + +- [x] Create a Hugo theme +- [x] Add task lists to it +- [ ] Take a vacation + +And a "mixed" task list: + +- [ ] Pack bags +- ? +- [ ] Travel! + +And a nested list: + +* Jackson 5 + * Michael + * Tito + * Jackie + * Marlon + * Jermaine +* TMNT + * Leonardo + * Michelangelo + * Donatello + * Raphael + +Definition lists can be used with Markdown syntax. Definition headers are bold. + +Name +: Godzilla + +Born +: 1952 + +Birthplace +: Japan + +Color +: Green + + +---------------- + +Tables should have bold headings and alternating shaded rows. + +| Artist | Album | Year | +|-------------------|-----------------|------| +| Michael Jackson | Thriller | 1982 | +| Prince | Purple Rain | 1984 | +| Beastie Boys | License to Ill | 1986 | + +If a table is too wide, it should scroll horizontally. + +| Artist | Album | Year | Label | Awards | Songs | +|-------------------|-----------------|------|-------------|----------|-----------| +| Michael Jackson | Thriller | 1982 | Epic Records | Grammy Award for Album of the Year, American Music Award for Favorite Pop/Rock Album, American Music Award for Favorite Soul/R&B Album, Brit Award for Best Selling Album, Grammy Award for Best Engineered Album, Non-Classical | Wanna Be Startin' Somethin', Baby Be Mine, The Girl Is Mine, Thriller, Beat It, Billie Jean, Human Nature, P.Y.T. (Pretty Young Thing), The Lady in My Life | +| Prince | Purple Rain | 1984 | Warner Brothers Records | Grammy Award for Best Score Soundtrack for Visual Media, American Music Award for Favorite Pop/Rock Album, American Music Award for Favorite Soul/R&B Album, Brit Award for Best Soundtrack/Cast Recording, Grammy Award for Best Rock Performance by a Duo or Group with Vocal | Let's Go Crazy, Take Me With U, The Beautiful Ones, Computer Blue, Darling Nikki, When Doves Cry, I Would Die 4 U, Baby I'm a Star, Purple Rain | +| Beastie Boys | License to Ill | 1986 | Mercury Records | noawardsbutthistablecelliswide | Rhymin & Stealin, The New Style, She's Crafty, Posse in Effect, Slow Ride, Girls, (You Gotta) Fight for Your Right, No Sleep Till Brooklyn, Paul Revere, Hold It Now, Hit It, Brass Monkey, Slow and Low, Time to Get Ill | + +---------------- + +Code snippets like `var foo = "bar";` can be shown inline. + +Also, `this should vertically align` ~~`with this`~~ ~~and this~~. + +Code can also be shown in a block element. + +``` +foo := "bar"; +bar := "foo"; +``` + +Code can also use syntax highlighting. + +```go +func main() { + input := `var foo = "bar";` + + lexer := lexers.Get("javascript") + iterator, _ := lexer.Tokenise(nil, input) + style := styles.Get("github") + formatter := html.New(html.WithLineNumbers()) + + var buff bytes.Buffer + formatter.Format(&buff, style, iterator) + + fmt.Println(buff.String()) +} +``` + +``` +Long, single-line code blocks should not wrap. They should horizontally scroll if they are too long. This line should be long enough to demonstrate this. +``` + +Inline code inside table cells should still be distinguishable. + +| Language | Code | +|-------------|--------------------| +| Javascript | `var foo = "bar";` | +| Ruby | `foo = "bar"{` | + +---------------- + +Small images should be shown at their actual size. + +![](https://upload.wikimedia.org/wikipedia/commons/thumb/9/9e/Picea_abies_shoot_with_buds%2C_Sogndal%2C_Norway.jpg/240px-Picea_abies_shoot_with_buds%2C_Sogndal%2C_Norway.jpg) + +Large images should always scale down and fit in the content container. + +![](https://upload.wikimedia.org/wikipedia/commons/thumb/9/9e/Picea_abies_shoot_with_buds%2C_Sogndal%2C_Norway.jpg/1024px-Picea_abies_shoot_with_buds%2C_Sogndal%2C_Norway.jpg) + +_The photo above of the Spruce Picea abies shoot with foliage buds: Bjørn Erik Pedersen, CC-BY-SA._ + + +## Components + +### Alerts + +{{< alert >}}This is an alert.{{< /alert >}} +{{< alert title="Note" >}}This is an alert with a title.{{< /alert >}} +{{% alert title="Note" %}}This is an alert with a title and **Markdown**.{{% /alert %}} +{{< alert color="success" >}}This is a successful alert.{{< /alert >}} +{{< alert color="warning" >}}This is a warning.{{< /alert >}} +{{< alert color="warning" title="Warning" >}}This is a warning with a title.{{< /alert >}} + + +## Another Heading + +Add some sections here to see how the ToC looks like. Bacon ipsum dolor sit amet t-bone doner shank drumstick, pork belly porchetta chuck sausage brisket ham hock rump pig. Chuck kielbasa leberkas, pork bresaola ham hock filet mignon cow shoulder short ribs biltong. + +### This Document + +Inguina genus: Anaphen post: lingua violente voce suae meus aetate diversi. Orbis unam nec flammaeque status deam Silenum erat et a ferrea. Excitus rigidum ait: vestro et Herculis convicia: nitidae deseruit coniuge Proteaque adiciam *eripitur*? Sitim noceat signa *probat quidem*. Sua longis *fugatis* quidem genae. + + +### Pixel Count + +Tilde photo booth wayfarers cliche lomo intelligentsia man braid kombucha vaporware farm-to-table mixtape portland. PBR&B pickled cornhole ugh try-hard ethical subway tile. Fixie paleo intelligentsia pabst. Ennui waistcoat vinyl gochujang. Poutine salvia authentic affogato, chambray lumbersexual shabby chic. + +### Contact Info + +Plaid hell of cred microdosing, succulents tilde pour-over. Offal shabby chic 3 wolf moon blue bottle raw denim normcore poutine pork belly. + + +### External Links + +Stumptown PBR&B keytar plaid street art, forage XOXO pitchfork selvage affogato green juice listicle pickled everyday carry hashtag. Organic sustainable letterpress sartorial scenester intelligentsia swag bushwick. Put a bird on it stumptown neutra locavore. IPhone typewriter messenger bag narwhal. Ennui cold-pressed seitan flannel keytar, single-origin coffee adaptogen occupy yuccie williamsburg chillwave shoreditch forage waistcoat. + + + +``` +This is the final element on the page and there should be no margin below this. +``` diff --git a/doc-site/content/en/docs2/Tutorials/_index.md b/doc-site/content/en/docs2/Tutorials/_index.md new file mode 100755 index 0000000..df2584d --- /dev/null +++ b/doc-site/content/en/docs2/Tutorials/_index.md @@ -0,0 +1,16 @@ + +--- +title: "Tutorials" +linkTitle: "Tutorials" +weight: 8 +date: 2017-01-04 +description: > + Show your user how to work through some end to end examples. +--- + +{{% pageinfo %}} +This is a placeholder page that shows you how to use this template site. +{{% /pageinfo %}} + +Tutorials are **complete worked examples** made up of **multiple tasks** that guide the user through a relatively simple but realistic scenario: building an application that uses some of your project’s features, for example. If you have already created some Examples for your project you can base Tutorials on them. This section is **optional**. However, remember that although you may not need this section at first, having tutorials can be useful to help your users engage with your example code, especially if there are aspects that need more explanation than you can easily provide in code comments. + diff --git a/doc-site/content/en/docs2/Tutorials/multi-bear.md b/doc-site/content/en/docs2/Tutorials/multi-bear.md new file mode 100644 index 0000000..0c07e1f --- /dev/null +++ b/doc-site/content/en/docs2/Tutorials/multi-bear.md @@ -0,0 +1,238 @@ +--- +title: "Multi-Bear Domicile Setup" +date: 2017-01-05 +weight: 4 +description: > + A short lead description about this content page. It can be **bold** or _italic_ and can be split over multiple paragraphs. +--- + +{{% pageinfo %}} +This is a placeholder page. Replace it with your own content. +{{% /pageinfo %}} + +Text can be **bold**, _italic_, or ~~strikethrough~~. [Links](https://gohugo.io) should be blue with no underlines (unless hovered over). + +There should be whitespace between paragraphs. Vape migas chillwave sriracha poutine try-hard distillery. Tattooed shabby chic small batch, pabst art party heirloom letterpress air plant pop-up. Sustainable chia skateboard art party banjo cardigan normcore affogato vexillologist quinoa meggings man bun master cleanse shoreditch readymade. Yuccie prism four dollar toast tbh cardigan iPhone, tumblr listicle live-edge VHS. Pug lyft normcore hot chicken biodiesel, actually keffiyeh thundercats photo booth pour-over twee fam food truck microdosing banh mi. Vice activated charcoal raclette unicorn live-edge post-ironic. Heirloom vexillologist coloring book, beard deep v letterpress echo park humblebrag tilde. + +90's four loko seitan photo booth gochujang freegan tumeric listicle fam ugh humblebrag. Bespoke leggings gastropub, biodiesel brunch pug fashion axe meh swag art party neutra deep v chia. Enamel pin fanny pack knausgaard tofu, artisan cronut hammock meditation occupy master cleanse chartreuse lumbersexual. Kombucha kogi viral truffaut synth distillery single-origin coffee ugh slow-carb marfa selfies. Pitchfork schlitz semiotics fanny pack, ugh artisan vegan vaporware hexagon. Polaroid fixie post-ironic venmo wolf ramps **kale chips**. + +> There should be no margin above this first sentence. +> +> Blockquotes should be a lighter gray with a border along the left side in the secondary color. +> +> There should be no margin below this final sentence. + +## First Header 2 + +This is a normal paragraph following a header. Knausgaard kale chips snackwave microdosing cronut copper mug swag synth bitters letterpress glossier **craft beer**. Mumblecore bushwick authentic gochujang vegan chambray meditation jean shorts irony. Viral farm-to-table kale chips, pork belly palo santo distillery activated charcoal aesthetic jianbing air plant woke lomo VHS organic. Tattooed locavore succulents heirloom, small batch sriracha echo park DIY af. Shaman you probably haven't heard of them copper mug, crucifix green juice vape *single-origin coffee* brunch actually. Mustache etsy vexillologist raclette authentic fam. Tousled beard humblebrag asymmetrical. I love turkey, I love my job, I love my friends, I love Chardonnay! + +Deae legum paulatimque terra, non vos mutata tacet: dic. Vocant docuique me plumas fila quin afuerunt copia haec o neque. + +On big screens, paragraphs and headings should not take up the full container width, but we want tables, code blocks and similar to take the full width. + +Scenester tumeric pickled, authentic crucifix post-ironic fam freegan VHS pork belly 8-bit yuccie PBR&B. **I love this life we live in**. + + +## Second Header 2 + +> This is a blockquote following a header. Bacon ipsum dolor sit amet t-bone doner shank drumstick, pork belly porchetta chuck sausage brisket ham hock rump pig. Chuck kielbasa leberkas, pork bresaola ham hock filet mignon cow shoulder short ribs biltong. + +### Header 3 + +``` +This is a code block following a header. +``` + +Next level leggings before they sold out, PBR&B church-key shaman echo park. Kale chips occupy godard whatever pop-up freegan pork belly selfies. Gastropub Belinda subway tile woke post-ironic seitan. Shabby chic man bun semiotics vape, chia messenger bag plaid cardigan. + +#### Header 4 + +* This is an unordered list following a header. +* This is an unordered list following a header. +* This is an unordered list following a header. + +##### Header 5 + +1. This is an ordered list following a header. +2. This is an ordered list following a header. +3. This is an ordered list following a header. + +###### Header 6 + +| What | Follows | +|-----------|-----------------| +| A table | A header | +| A table | A header | +| A table | A header | + +---------------- + +There's a horizontal rule above and below this. + +---------------- + +Here is an unordered list: + +* Liverpool F.C. +* Chelsea F.C. +* Manchester United F.C. + +And an ordered list: + +1. Michael Brecker +2. Seamus Blake +3. Branford Marsalis + +And an unordered task list: + +- [x] Create a Hugo theme +- [x] Add task lists to it +- [ ] Take a vacation + +And a "mixed" task list: + +- [ ] Pack bags +- ? +- [ ] Travel! + +And a nested list: + +* Jackson 5 + * Michael + * Tito + * Jackie + * Marlon + * Jermaine +* TMNT + * Leonardo + * Michelangelo + * Donatello + * Raphael + +Definition lists can be used with Markdown syntax. Definition headers are bold. + +Name +: Godzilla + +Born +: 1952 + +Birthplace +: Japan + +Color +: Green + + +---------------- + +Tables should have bold headings and alternating shaded rows. + +| Artist | Album | Year | +|-------------------|-----------------|------| +| Michael Jackson | Thriller | 1982 | +| Prince | Purple Rain | 1984 | +| Beastie Boys | License to Ill | 1986 | + +If a table is too wide, it should scroll horizontally. + +| Artist | Album | Year | Label | Awards | Songs | +|-------------------|-----------------|------|-------------|----------|-----------| +| Michael Jackson | Thriller | 1982 | Epic Records | Grammy Award for Album of the Year, American Music Award for Favorite Pop/Rock Album, American Music Award for Favorite Soul/R&B Album, Brit Award for Best Selling Album, Grammy Award for Best Engineered Album, Non-Classical | Wanna Be Startin' Somethin', Baby Be Mine, The Girl Is Mine, Thriller, Beat It, Billie Jean, Human Nature, P.Y.T. (Pretty Young Thing), The Lady in My Life | +| Prince | Purple Rain | 1984 | Warner Brothers Records | Grammy Award for Best Score Soundtrack for Visual Media, American Music Award for Favorite Pop/Rock Album, American Music Award for Favorite Soul/R&B Album, Brit Award for Best Soundtrack/Cast Recording, Grammy Award for Best Rock Performance by a Duo or Group with Vocal | Let's Go Crazy, Take Me With U, The Beautiful Ones, Computer Blue, Darling Nikki, When Doves Cry, I Would Die 4 U, Baby I'm a Star, Purple Rain | +| Beastie Boys | License to Ill | 1986 | Mercury Records | noawardsbutthistablecelliswide | Rhymin & Stealin, The New Style, She's Crafty, Posse in Effect, Slow Ride, Girls, (You Gotta) Fight for Your Right, No Sleep Till Brooklyn, Paul Revere, Hold It Now, Hit It, Brass Monkey, Slow and Low, Time to Get Ill | + +---------------- + +Code snippets like `var foo = "bar";` can be shown inline. + +Also, `this should vertically align` ~~`with this`~~ ~~and this~~. + +Code can also be shown in a block element. + +``` +foo := "bar"; +bar := "foo"; +``` + +Code can also use syntax highlighting. + +```go +func main() { + input := `var foo = "bar";` + + lexer := lexers.Get("javascript") + iterator, _ := lexer.Tokenise(nil, input) + style := styles.Get("github") + formatter := html.New(html.WithLineNumbers()) + + var buff bytes.Buffer + formatter.Format(&buff, style, iterator) + + fmt.Println(buff.String()) +} +``` + +``` +Long, single-line code blocks should not wrap. They should horizontally scroll if they are too long. This line should be long enough to demonstrate this. +``` + +Inline code inside table cells should still be distinguishable. + +| Language | Code | +|-------------|--------------------| +| Javascript | `var foo = "bar";` | +| Ruby | `foo = "bar"{` | + +---------------- + +Small images should be shown at their actual size. + +![](https://upload.wikimedia.org/wikipedia/commons/thumb/9/9e/Picea_abies_shoot_with_buds%2C_Sogndal%2C_Norway.jpg/240px-Picea_abies_shoot_with_buds%2C_Sogndal%2C_Norway.jpg) + +Large images should always scale down and fit in the content container. + +![](https://upload.wikimedia.org/wikipedia/commons/thumb/9/9e/Picea_abies_shoot_with_buds%2C_Sogndal%2C_Norway.jpg/1024px-Picea_abies_shoot_with_buds%2C_Sogndal%2C_Norway.jpg) + +_The photo above of the Spruce Picea abies shoot with foliage buds: Bjørn Erik Pedersen, CC-BY-SA._ + + +## Components + +### Alerts + +{{< alert >}}This is an alert.{{< /alert >}} +{{< alert title="Note" >}}This is an alert with a title.{{< /alert >}} +{{% alert title="Note" %}}This is an alert with a title and **Markdown**.{{% /alert %}} +{{< alert color="success" >}}This is a successful alert.{{< /alert >}} +{{< alert color="warning" >}}This is a warning.{{< /alert >}} +{{< alert color="warning" title="Warning" >}}This is a warning with a title.{{< /alert >}} + + +## Another Heading + +Add some sections here to see how the ToC looks like. Bacon ipsum dolor sit amet t-bone doner shank drumstick, pork belly porchetta chuck sausage brisket ham hock rump pig. Chuck kielbasa leberkas, pork bresaola ham hock filet mignon cow shoulder short ribs biltong. + +### This Document + +Inguina genus: Anaphen post: lingua violente voce suae meus aetate diversi. Orbis unam nec flammaeque status deam Silenum erat et a ferrea. Excitus rigidum ait: vestro et Herculis convicia: nitidae deseruit coniuge Proteaque adiciam *eripitur*? Sitim noceat signa *probat quidem*. Sua longis *fugatis* quidem genae. + + +### Pixel Count + +Tilde photo booth wayfarers cliche lomo intelligentsia man braid kombucha vaporware farm-to-table mixtape portland. PBR&B pickled cornhole ugh try-hard ethical subway tile. Fixie paleo intelligentsia pabst. Ennui waistcoat vinyl gochujang. Poutine salvia authentic affogato, chambray lumbersexual shabby chic. + +### Contact Info + +Plaid hell of cred microdosing, succulents tilde pour-over. Offal shabby chic 3 wolf moon blue bottle raw denim normcore poutine pork belly. + + +### External Links + +Stumptown PBR&B keytar plaid street art, forage XOXO pitchfork selvage affogato green juice listicle pickled everyday carry hashtag. Organic sustainable letterpress sartorial scenester intelligentsia swag bushwick. Put a bird on it stumptown neutra locavore. IPhone typewriter messenger bag narwhal. Ennui cold-pressed seitan flannel keytar, single-origin coffee adaptogen occupy yuccie williamsburg chillwave shoreditch forage waistcoat. + + + +``` +This is the final element on the page and there should be no margin below this. +``` diff --git a/doc-site/content/en/docs2/Tutorials/tutorial2.md b/doc-site/content/en/docs2/Tutorials/tutorial2.md new file mode 100644 index 0000000..0cad5b5 --- /dev/null +++ b/doc-site/content/en/docs2/Tutorials/tutorial2.md @@ -0,0 +1,238 @@ +--- +title: "Another Tutorial" +date: 2017-01-05 +weight: 5 +description: > + A short lead description about this content page. It can be **bold** or _italic_ and can be split over multiple paragraphs. +--- + +{{% pageinfo %}} +This is a placeholder page. Replace it with your own content. +{{% /pageinfo %}} + +Text can be **bold**, _italic_, or ~~strikethrough~~. [Links](https://gohugo.io) should be blue with no underlines (unless hovered over). + +There should be whitespace between paragraphs. Vape migas chillwave sriracha poutine try-hard distillery. Tattooed shabby chic small batch, pabst art party heirloom letterpress air plant pop-up. Sustainable chia skateboard art party banjo cardigan normcore affogato vexillologist quinoa meggings man bun master cleanse shoreditch readymade. Yuccie prism four dollar toast tbh cardigan iPhone, tumblr listicle live-edge VHS. Pug lyft normcore hot chicken biodiesel, actually keffiyeh thundercats photo booth pour-over twee fam food truck microdosing banh mi. Vice activated charcoal raclette unicorn live-edge post-ironic. Heirloom vexillologist coloring book, beard deep v letterpress echo park humblebrag tilde. + +90's four loko seitan photo booth gochujang freegan tumeric listicle fam ugh humblebrag. Bespoke leggings gastropub, biodiesel brunch pug fashion axe meh swag art party neutra deep v chia. Enamel pin fanny pack knausgaard tofu, artisan cronut hammock meditation occupy master cleanse chartreuse lumbersexual. Kombucha kogi viral truffaut synth distillery single-origin coffee ugh slow-carb marfa selfies. Pitchfork schlitz semiotics fanny pack, ugh artisan vegan vaporware hexagon. Polaroid fixie post-ironic venmo wolf ramps **kale chips**. + +> There should be no margin above this first sentence. +> +> Blockquotes should be a lighter gray with a border along the left side in the secondary color. +> +> There should be no margin below this final sentence. + +## First Header 2 + +This is a normal paragraph following a header. Knausgaard kale chips snackwave microdosing cronut copper mug swag synth bitters letterpress glossier **craft beer**. Mumblecore bushwick authentic gochujang vegan chambray meditation jean shorts irony. Viral farm-to-table kale chips, pork belly palo santo distillery activated charcoal aesthetic jianbing air plant woke lomo VHS organic. Tattooed locavore succulents heirloom, small batch sriracha echo park DIY af. Shaman you probably haven't heard of them copper mug, crucifix green juice vape *single-origin coffee* brunch actually. Mustache etsy vexillologist raclette authentic fam. Tousled beard humblebrag asymmetrical. I love turkey, I love my job, I love my friends, I love Chardonnay! + +Deae legum paulatimque terra, non vos mutata tacet: dic. Vocant docuique me plumas fila quin afuerunt copia haec o neque. + +On big screens, paragraphs and headings should not take up the full container width, but we want tables, code blocks and similar to take the full width. + +Scenester tumeric pickled, authentic crucifix post-ironic fam freegan VHS pork belly 8-bit yuccie PBR&B. **I love this life we live in**. + + +## Second Header 2 + +> This is a blockquote following a header. Bacon ipsum dolor sit amet t-bone doner shank drumstick, pork belly porchetta chuck sausage brisket ham hock rump pig. Chuck kielbasa leberkas, pork bresaola ham hock filet mignon cow shoulder short ribs biltong. + +### Header 3 + +``` +This is a code block following a header. +``` + +Next level leggings before they sold out, PBR&B church-key shaman echo park. Kale chips occupy godard whatever pop-up freegan pork belly selfies. Gastropub Belinda subway tile woke post-ironic seitan. Shabby chic man bun semiotics vape, chia messenger bag plaid cardigan. + +#### Header 4 + +* This is an unordered list following a header. +* This is an unordered list following a header. +* This is an unordered list following a header. + +##### Header 5 + +1. This is an ordered list following a header. +2. This is an ordered list following a header. +3. This is an ordered list following a header. + +###### Header 6 + +| What | Follows | +|-----------|-----------------| +| A table | A header | +| A table | A header | +| A table | A header | + +---------------- + +There's a horizontal rule above and below this. + +---------------- + +Here is an unordered list: + +* Liverpool F.C. +* Chelsea F.C. +* Manchester United F.C. + +And an ordered list: + +1. Michael Brecker +2. Seamus Blake +3. Branford Marsalis + +And an unordered task list: + +- [x] Create a Hugo theme +- [x] Add task lists to it +- [ ] Take a vacation + +And a "mixed" task list: + +- [ ] Pack bags +- ? +- [ ] Travel! + +And a nested list: + +* Jackson 5 + * Michael + * Tito + * Jackie + * Marlon + * Jermaine +* TMNT + * Leonardo + * Michelangelo + * Donatello + * Raphael + +Definition lists can be used with Markdown syntax. Definition headers are bold. + +Name +: Godzilla + +Born +: 1952 + +Birthplace +: Japan + +Color +: Green + + +---------------- + +Tables should have bold headings and alternating shaded rows. + +| Artist | Album | Year | +|-------------------|-----------------|------| +| Michael Jackson | Thriller | 1982 | +| Prince | Purple Rain | 1984 | +| Beastie Boys | License to Ill | 1986 | + +If a table is too wide, it should scroll horizontally. + +| Artist | Album | Year | Label | Awards | Songs | +|-------------------|-----------------|------|-------------|----------|-----------| +| Michael Jackson | Thriller | 1982 | Epic Records | Grammy Award for Album of the Year, American Music Award for Favorite Pop/Rock Album, American Music Award for Favorite Soul/R&B Album, Brit Award for Best Selling Album, Grammy Award for Best Engineered Album, Non-Classical | Wanna Be Startin' Somethin', Baby Be Mine, The Girl Is Mine, Thriller, Beat It, Billie Jean, Human Nature, P.Y.T. (Pretty Young Thing), The Lady in My Life | +| Prince | Purple Rain | 1984 | Warner Brothers Records | Grammy Award for Best Score Soundtrack for Visual Media, American Music Award for Favorite Pop/Rock Album, American Music Award for Favorite Soul/R&B Album, Brit Award for Best Soundtrack/Cast Recording, Grammy Award for Best Rock Performance by a Duo or Group with Vocal | Let's Go Crazy, Take Me With U, The Beautiful Ones, Computer Blue, Darling Nikki, When Doves Cry, I Would Die 4 U, Baby I'm a Star, Purple Rain | +| Beastie Boys | License to Ill | 1986 | Mercury Records | noawardsbutthistablecelliswide | Rhymin & Stealin, The New Style, She's Crafty, Posse in Effect, Slow Ride, Girls, (You Gotta) Fight for Your Right, No Sleep Till Brooklyn, Paul Revere, Hold It Now, Hit It, Brass Monkey, Slow and Low, Time to Get Ill | + +---------------- + +Code snippets like `var foo = "bar";` can be shown inline. + +Also, `this should vertically align` ~~`with this`~~ ~~and this~~. + +Code can also be shown in a block element. + +``` +foo := "bar"; +bar := "foo"; +``` + +Code can also use syntax highlighting. + +```go +func main() { + input := `var foo = "bar";` + + lexer := lexers.Get("javascript") + iterator, _ := lexer.Tokenise(nil, input) + style := styles.Get("github") + formatter := html.New(html.WithLineNumbers()) + + var buff bytes.Buffer + formatter.Format(&buff, style, iterator) + + fmt.Println(buff.String()) +} +``` + +``` +Long, single-line code blocks should not wrap. They should horizontally scroll if they are too long. This line should be long enough to demonstrate this. +``` + +Inline code inside table cells should still be distinguishable. + +| Language | Code | +|-------------|--------------------| +| Javascript | `var foo = "bar";` | +| Ruby | `foo = "bar"{` | + +---------------- + +Small images should be shown at their actual size. + +![](https://upload.wikimedia.org/wikipedia/commons/thumb/9/9e/Picea_abies_shoot_with_buds%2C_Sogndal%2C_Norway.jpg/240px-Picea_abies_shoot_with_buds%2C_Sogndal%2C_Norway.jpg) + +Large images should always scale down and fit in the content container. + +![](https://upload.wikimedia.org/wikipedia/commons/thumb/9/9e/Picea_abies_shoot_with_buds%2C_Sogndal%2C_Norway.jpg/1024px-Picea_abies_shoot_with_buds%2C_Sogndal%2C_Norway.jpg) + +_The photo above of the Spruce Picea abies shoot with foliage buds: Bjørn Erik Pedersen, CC-BY-SA._ + + +## Components + +### Alerts + +{{< alert >}}This is an alert.{{< /alert >}} +{{< alert title="Note" >}}This is an alert with a title.{{< /alert >}} +{{% alert title="Note" %}}This is an alert with a title and **Markdown**.{{% /alert %}} +{{< alert color="success" >}}This is a successful alert.{{< /alert >}} +{{< alert color="warning" >}}This is a warning.{{< /alert >}} +{{< alert color="warning" title="Warning" >}}This is a warning with a title.{{< /alert >}} + + +## Another Heading + +Add some sections here to see how the ToC looks like. Bacon ipsum dolor sit amet t-bone doner shank drumstick, pork belly porchetta chuck sausage brisket ham hock rump pig. Chuck kielbasa leberkas, pork bresaola ham hock filet mignon cow shoulder short ribs biltong. + +### This Document + +Inguina genus: Anaphen post: lingua violente voce suae meus aetate diversi. Orbis unam nec flammaeque status deam Silenum erat et a ferrea. Excitus rigidum ait: vestro et Herculis convicia: nitidae deseruit coniuge Proteaque adiciam *eripitur*? Sitim noceat signa *probat quidem*. Sua longis *fugatis* quidem genae. + + +### Pixel Count + +Tilde photo booth wayfarers cliche lomo intelligentsia man braid kombucha vaporware farm-to-table mixtape portland. PBR&B pickled cornhole ugh try-hard ethical subway tile. Fixie paleo intelligentsia pabst. Ennui waistcoat vinyl gochujang. Poutine salvia authentic affogato, chambray lumbersexual shabby chic. + +### Contact Info + +Plaid hell of cred microdosing, succulents tilde pour-over. Offal shabby chic 3 wolf moon blue bottle raw denim normcore poutine pork belly. + + +### External Links + +Stumptown PBR&B keytar plaid street art, forage XOXO pitchfork selvage affogato green juice listicle pickled everyday carry hashtag. Organic sustainable letterpress sartorial scenester intelligentsia swag bushwick. Put a bird on it stumptown neutra locavore. IPhone typewriter messenger bag narwhal. Ennui cold-pressed seitan flannel keytar, single-origin coffee adaptogen occupy yuccie williamsburg chillwave shoreditch forage waistcoat. + + + +``` +This is the final element on the page and there should be no margin below this. +``` diff --git a/doc-site/content/en/docs2/_index.md b/doc-site/content/en/docs2/_index.md new file mode 100755 index 0000000..d5ec96a --- /dev/null +++ b/doc-site/content/en/docs2/_index.md @@ -0,0 +1,24 @@ + +--- +title: "Documentation" +linkTitle: "Documentation" +weight: 20 +menu: + main: + weight: 20 +--- + +{{% pageinfo %}} +This is a placeholder page that shows you how to use this template site. +{{% /pageinfo %}} + + +This section is where the user documentation for your project lives - all the information your users need to understand and successfully use your project. + +For large documentation sets we recommend adding content under the headings in this section, though if some or all of them don’t apply to your project feel free to remove them or add your own. You can see an example of a smaller Docsy documentation site in the [Docsy User Guide](https://docsy.dev/docs/), which lives in the [Docsy theme repo](https://github.com/google/docsy/tree/master/userguide) if you'd like to copy its docs section. + +Other content such as marketing material, case studies, and community updates should live in the [About](/about/) and [Community](/community/) pages. + +Find out how to use the Docsy theme in the [Docsy User Guide](https://docsy.dev/docs/). You can learn more about how to organize your documentation (and how we organized this site) in [Organizing Your Content](https://docsy.dev/docs/best-practices/organizing-content/). + + diff --git a/doc-site/content/en/ignore/guide.adoc b/doc-site/content/en/ignore/guide.adoc new file mode 100644 index 0000000..88ccdde --- /dev/null +++ b/doc-site/content/en/ignore/guide.adoc @@ -0,0 +1,1086 @@ +--- +title: "Programming Guide" +--- + += Behavior Graph +:icons: font +:imagesdir: ../images +:sectlinks: +:source-highlighter: rouge +:rouge-theme: molokai +:toc: left +//:bg-doc-version: objc +:bg-doc-version: typescript + + +include::content/en/includes.adoc[tag={bg-doc-version}] + +== The Basics + +=== Login button + +[[login_example1, Login page example]] +.Login page example +==== + +Our first example implements a standard login page. + +image::login_ui.png[Login Page] + +* A login button should be enabled if a valid email and password have been entered. +* A valid email has standard email formatting. +* A valid password is non-empty. +* As the user types into those fields, the enabled state of the login button will update automatically. +==== + +=== A behavior is a unit of functionality + +*Behaviors* are the fundamental unit of composition when using Behavior Graph. +They are blocks of code along with the dependency relationships they are involved in. + +==== +Here is the behavior that implements our <>. +It gets run whenever the email and password fields change. +It validates those fields and updates the enabled state of the login button accordingly. + +[source, {source-language}, numbered, indent=0] +[[login_behavior]] +.Login behavior +---- +include::{sourcedir}/{example-loginextent}[tags=login_enable_behavior] +---- +==== + +The bulk of your code will comprise of many behaviors similar to this one. +Without worrying too much about some unfamiliar details, keep in mind that code inside a behavior is normal code: + +* Conventional programming constructs: property access, method calls, and boolean expressions. +* Platform standard API calls for interacting with the environment + +=== A resource is a unit of state + +*Resources* carry state in a controlled manner. +Resources store information about the system you are modeling. + +==== +[source, {source-language}, numbered, indent=0] +.Login behavior +---- +include::{sourcedir}/{example-loginextent}[tags=login_enable_behavior] +---- +* Line 1 of references the `email` and `password` properties. +These are both resources. +* {source-resource-1} access the same properties via the `extent` object passed into the block. + +`email` contains the current textual content of the email UI element. +`password` plays a similar role. +==== + +=== Extents are collections of related behaviors and resources + +*Extents* are specialized containers for behaviors and resources. +You must subclass `{extent-class}`. +On your subclass: + +1. Define resources as properties. +2. Initialize resources in the {constructor}. +3. Create behaviors in the {constructor}. + +==== +<> needs only a single extent, `LoginExtent`. +`email` and `password` are defined as properties. + +[source, {source-language}, numbered, indent=0] +---- +include::{sourcedir}/{example-loginextent-header}[tags=login_enable_extent] +---- + +`{state-class}` is a resource subtype for retaining state. +Here they are specialized on the type `{string-class}` for holding the contents of their respective text fields. +Inside the {constructor} we create the graph elements + +[source, {source-language}, numbered, indent=0] +---- +include::{sourcedir}/{example-loginextent}[tags=login_enable_init] +---- +==== + +ifdef::uses-crtp[] +IMPORTANT: Remember to specify your `{extent-class}` subclass with the generic parameter as the subclass itself. +This unusual syntax is an instance of the link:https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern[curiously recurring template pattern]. +It is a known technique which lets us be more precise with our types without having to override some common methods, specifically `{behavior-method}` and `{sideeffect-method}`. +endif::[] + +=== {state-class} resources retain information + +`{state-class}` is a type of resource. +It is generic on the type of its contents. + +Initial contents are supplied in the {constructor}. + +Use the `value` property to access its contents. + +Calling `{update-method}` on it will update those contents. +The contents will remain the same until `{update-method}` is called again with different information. + +ifeval::["{bg-doc-version}" == "objc"] +NOTE: Objective-C "implements" generics with pointer types. +Therefore storing native types such as booleans and numbers in instances of `{state-class}` requires the use of Objective-C's boxed types such as `NSNumber`. +endif::[] + +=== Demands are the resources a behavior depends on + +A behavior has read-only access to a set of resources it depends on called *demands*. +Behavior Graph uses this dependency information to run the behavior at the correct time. + +You must explicitly set the demands on a behavior either when creating a behavior or via the `setDemands` method. + +Accessing the `value` property from inside a behavior without specifying it as a demand will raise an error. + +Calling `{update-method}` on a demanded resource will also raise an error. +It is read-only. + +==== +In order to determine if the login button should be enabled, our login behavior needs access the information stored in the `email` and `password` resources. + +[source, {source-language}, numbered, indent=0] +.Login behavior +---- +include::{sourcedir}/{example-loginextent}[tags=login_enable_behavior] +---- +* Line 1 initializes the behavior with an array containing these resources as demands. +* {source-resource-1} are able to access the stored contents of `email` and `password` via the `value` property. +This is because they are listed as demands in line 1. + +==== + +=== Input happens via actions + +The *environment* is everything that is not part of your Behavior Graph subsystem. +In order to track changes to that environment, you program must create new *actions* via the `{action-method}` method on the graph object. +Inside that you are able to update the contents of resources. + +==== +As the user types into the email and password fields, we want our program to react by updating the enabled state of the login button. +Those UI fields are part of the environment. +So we write handlers for those fields which will create new actions as those fields change. + +[source, {source-language}, numbered, indent=0] +[[login_actions]] +.Login actions +---- +include::{sourcedir}/{example-loginpage}[tags=login_enable_actions] +---- + +* Line 1 is a typical callback method that is called from the UI framework when the email text field is updated. +* Line 2 creates a new action block. +* Line 3 updates the contents of the `email` resource using the `{update-method}` method. +This is the same resource instance that is accessed in <>. +==== + +TIP: Action blocks are initialized with an optional string called the *impulse*. +The impulse is a debugging aid to help answer the question, "why is this happening?". + +=== Updating a resource causes its demanding behaviors to be activated + +Calling `{update-method}` on a resource will change the information stored in that resource. +When the value changes, any behavior that demands that resource will be *activated*. +Activated behaviors are put into an internal queue to run in the correct order. + +==== +* Each time the user types characters into the email field, the `didUpdateEmailField` will run, creating a new action block. +* When that action block runs, the `email` resource will update to contain the current contents of the email field. +* The <> demands the `email` resource, so it activates. +==== + +=== The next activated behavior will run after the current action or behavior completes + +After the current action or behavior block completes, the Behavior Graph will check if any there are any activated behaviors on its internal queue. +If so it will remove the top one from the queue and run it. +This will continue until there are no more activated behaviors on the queue. + +==== +* After the action block completes in <>, the activated behavior <> will run. +==== + +=== Side effects create output in the environment + +While a behavior is running, it may determine that changing circumstances warrant a reaction in the environment. +Create this mechanism for output by calling `{sideeffect-method}` on the current extent. + +All interactions with the environment that do something should happen through *side effects*. +This lets the Behavior Graph runtime postpone changes to the environment until after any state changes. + +==== +[source, {source-language}, numbered, indent=0] +.Login behavior +---- +include::{sourcedir}/{example-loginextent}[tags=login_enable_behavior] +---- +* {source-sideeffect-1} creates a side effect. +* The next line updates the `enabled` state of the UI element by making a call directly to the platform user interface API. +==== + +TIP: The string parameter to `{sideeffect-method}` is an aid for debugging. + +=== Behavior Graph is a graph + +*Behavior Graph diagrams* provide a compact visual overview of the elements involved in your system. + +==== +With our actions, resources, behavior, and side effect, <> takes on the distinctive characteristics of a graph. + +image::login_simple_diagram.png[Login Diagram] + +* `email` and `password` rectangles are resources. +* The dashed boxes around them are actions. +* The dashed box around `enable login button` is a side effect. +* The solid box around it is the behavior. +That behavior demands those resources as indicated by the connecting lines. +==== + +=== There is a graph instance + +A program will need at least one instance of `{graph-class}`. +This object connects all behaviors, resources, and extents involved in your system. +It is responsible for running behavior code blocks in the correct order and ensuring relationships are valid. + +Create a single instance of `{graph-class}` and make it available to any object which will work with Behavior Graph code. +Then add your extent instances inside an action and the `{addtograph-method}` method. + +==== + +In the root application code, we create an instance of the `LoginExtent` and add it to our graph. + +[source, {source-language}, numbered, indent=0] +---- +include::{sourcedir}/{example-loginpage}[tags=login_enable_setup] +---- + +Line 2 creates a new action on this graph object inside which we add our `LoginExtent` instance. + +==== + +=== An Event is a single run through the graph + +An *event* begins with the running of an action block. +The behavior graph will continue to run activated behaviors until there are none left. +It will then run side effects in the order they were created. +When there are no remaining side effects, the event will complete. + +==== +Assume the user has just typed a character into the email text field which now contains the letters "sal": + +1. The `didUpdateEmailField` method is called, which creates a new action. +2. The graph object will run the action block. +3. Inside the action block the `email` resource is updated to contain the string "sal"/ +4. The updated resource activates the login behavior. +5. The action block completes. +6. The graph object sees only one behavior has been activated and runs it. +7. The behavior code block runs, determines email is invalid and creates a side effect to disable the login button. +8. The behavior code block completes. +9. With no more activated behaviors, the graph object runs the only side effect. +10. The side effect block runs the code to disable the login button. + +This is all part of a single event. +When the user types an additional character a new event will run. +==== + +== Getting Deeper + +=== Complete login page example + +[[login_example2, Complete login page]] +.Complete login page +==== + +We can extend our prior example to include the asynchronous interactions for logging in. + +image::login_ui_complete.png[Complete login page] + +This Behavior Graph diagram includes the additional elements and relationships to support the following additional features: + +* Clicking on the login button, when enabled, will make a remote API call with the user's credentials. +* While the login API call is being made the button will disable. +* Tapping the return key will also initiate a login. +* Tapping the return key while the login button is disabled will not login. +* If the API call returns an error, the login button will reenable. +==== + +=== Behaviors are units of state management + +The most common role of a behavior is to synthesize new information based on its demands. + +It stores this information in resources called it's *supplies*. +These are resources to which it has read-write access. + +A behavior can call `{update-method}` and access the `value` property on any resource that it supplies. + +A behavior can supply any number of resources. + +==== +This behavior reacts to changes to the email text field by updating its `emailValid` resource based on the contents of the `email` resource. + +[source, {source-language}, numbered, indent=0] +[[login_email_valid]] +.Login email valid +---- +include::{sourcedir}/{example-loginextent}[tags=login_complete_email] +---- + +* Line 1 initializes the `emailValid` resource, a `{state-class}` resource on the `LoginExtent` object. +Its initial value is `{false-bool}`. +* The {behavior-method} method includes `emailValid` in its list of supplied resources in its second parameter. +* {source-statemanagement-1} calls `{update-method}` to update the contents of `emailValid`. +ifeval::["{bg-doc-version}" == "objc"] +Note that we use `@(emailValid)` to provide the boxed `NSNumber*` form of the boolean value. +endif::[] + + +`passwordValid` receives a similar treatment. +==== + +=== Resource updates activate behaviors + +The primary reason a behavior runs during any given event is that one or more of its demanded resources has updated. + +==== +As the user types into the email text field, the `email` resource updates. +When it updates, the behavior that supplies `emailValid` activates. +It will be run during the same event. + +The similar behavior that supplies `passwordValid` will not activate during this event. +Therefore it will not run. +This is because the `password` resource did not update. +==== + +=== Updates filter for equality + +ifeval::["{bg-doc-version}" == "objc"] +`{update-method}` changes the contents of a resource if the new value does not equal the current value. +endif::[] +ifeval::["{bg-doc-version}" != "objc"] +`{update-method}` takes an additional parameter indicating whether the update should filter out new values that are the same as the current value. +Passing `{true-bool}` in the second parameter will enable this filter. +endif::[] +If the contents are the same, say updating from `{false-bool}` to `{false-bool}`, then this version of `{update-method}` does nothing. +Therefore no demanding behavior will activate. +Behavior Graph uses the standard platform equality check inside `{update-method}`. + +ifeval::["{bg-doc-version}" == "objc"] +There is also a `updateValueForce` method which will always register as an update without doing an internal equality check. +endif::[] +ifeval::["{bg-doc-version}" != "objc"] +Passing `{false-bool}` as the second parameter will perform no additional check. +endif::[] +Using this, any demanding behaviors will always be activated. + +==== +[source, {source-language}, numbered, indent=0] +.Login email valid +---- +include::{sourcedir}/{example-loginextent}[tags=login_complete_email] +---- +* On line 1, the `emailValid` resource is initialized with `{false-bool}`. +As the user begins to type into the email text field it will not be a valid email. +* {source-statemanagement-1} calls `{update-method}` on `emailValid`. Setting it to `{false-bool}` again will do nothing because we filter out the equality. +The login enabling behavior which demands this resource will not activate. +* When the user finally types in a valid email, `emailValid` will change to `{true-bool}`, which will activate and subsequently run the login enabling behavior. +==== + +TIP: Equality in programming is a nuanced topic, to say the least. +If the default method does not work for you, skip the equality check and perform your own. + +=== Moment resources capture transient knowledge + +In contrast to State resources, Moment resources capture information about what is happening only during the current event. +A button click or a key press are moments. + +Moments are instances of `{moment-class}`. + +Calling `{momentupdate-method}` on a moment instance inside an action or supplying behavior will capture the idea that it happened. + +Querying a moment's `{momentjustupdated-method}` property will determine if the moment happened during the current event. + +Some moments may contain no information beyond merely happening, such as a button click. +Other moments, such as a successful network response, may also have additional information that you will wish to capture. +A moment instance will be generic on the type of its contents. +Pass in this additional information as a parameter to the `{momentupdate-method}` method. +Query this information using the `value` property. + +Moments are transient. +The contents are only available during the event that they happen. +They will be forgotten at the end of the event. + +==== +`loginClick` and `returnKey` are both moments that update when the user clicks on the button or taps the return key. +Neither has any additional contents. + +[source, {source-language}, numbered, indent=0] +[[login_complete_click]] +.Login click +---- +include::{sourcedir}/{example-loginpage}[tags=login_complete_click] +---- +==== + +NOTE: Behavior Graph diagrams show moments as resources with a cutout in the top right corner. + +=== Moments activate behaviors when they happen + +Similar to a state change in state resources, when a moment happens it is considered updated. +Any behaviors that demand it will activate. + +Behaviors that demand moments will frequently check `{momentjustupdated-method}` to determine how to react during the current event. + +==== +This behavior decides when to log in and updates the logging in state. +`loggingIn` is a state resource, while `loginComplete` captures the moment know our login API call has succeeded. + +[source, {source-language}, numbered, indent=0] +[[login_login]] +.Logging in behavior +---- +include::{sourcedir}/{example-loginextent}[tags=login_complete_login] +---- + +* The first clause of the `if` statement responds to clicking the login button or pressing the return key to start the login API call. +* The second clause responds to the completed network call, putting us in a logged in state. +* Lastly if we have just entered the logging in state, we will initiate that API call. + +==== + +=== State changes can be queried + +State resources have a `{statejustupdated-method}` property. +It is only true during the event in which a successful `{update-method}` occurs. + +For more precision, there are also `{statejustupdatedto-method}` and `{statejustupdatedtofrom-method}` methods. +This check can be done in the same behavior that supplies the resource or any behavior that demands it. + +==== +* {source-justupdated-1} of <> updates the value of `loggingIn` to {true-bool} when the user clicks the button or presses the return key. +* {source-justupdated-2} then checks that same resource via `{statejustupdatedto-method}` in order to determine if the system should do the actual side effect of calling the login API method. +==== + +=== Updates activate behaviors + +A typical behavior graph program will consist of many state and moment resources. +It is useful to be able to talk about the general idea behind "happening" or "changing". +This term is called *updating*. + +When a resource updates, any behaviors that demand it will be activated. + +Updates can only be checked for inside a behavior if that behavior demands or supplies that resource. +Doing otherwise is an error + +=== Updates can only come from actions or behaviors + +If the update comes from a behavior, that resource must be supplied by that behavior. +A resource may be supplied by _only one behavior_. + +If a resource is not supplied by a behavior may it be updated inside an action. + +These rules guarantee that a resource will be updated only once per event. + +== How it Works + +=== Behavior Graph is a bipartite directed acyclic graph + +The graph of the Behavior Graph contains two node types, resources and behaviors, making it a bipartite graph. + +Edges are the links between resources and behaviors. + +.Graph example +[[graph_example, Graph example]] +==== +image::graph_example.png[Graph example] +==== + +Specifically this is a dataflow dependency graph which has a few simple rules: + +* Resources can only point to (demanded by) behaviors +* Behaviors can only point to (supply) resources +* A resource can be demanded by any number of behaviors (B1 demands R2 and B2 demands R2) +* A behavior can supply to 0 or more resources (B1 supplies R5 and R4) +* A resource can be supplied by either: + ** 0 behaviors (R1 has no supplier, therefore it is updated in an action) + ** 1 behavior (R5 is supplied only by B1) +* No cycles are permitted + +These rules combine to guarantee that during any event, each behavior will be run no more than once, and each resource will update in at most one place. + +=== Behavior Graph runs code in the correct order + +The value proposition for the Behavior Graph comes down to letting the computer manage control flow. +Control flow means deciding what code should run next. + +After completing an action or behavior, the Behavior Graph will select the next behavior off the queue to run. +However there may be multiple behaviors on that queue waiting to run. +Behavior Graph uses a priority queue based on the topological ordering of all the behaviors in the graph. + +==== +We can see how this matters looking at <>. + +1. When *R1* is updated, the graph knows that *B1* should be run next. +2. When *R2* is updated however, both *B1* and *B2* are activated. +3. The graph must run *B1* first because *B1* may update *R5* which is another demand of *B2*. +==== + +=== Graph cycles are not permitted + +Behavior Graph will throw an error when a graph cycle is detected as extents are added to the graph. +However, cycles can be easy to create. + +==== +Referring to <>, a potential cyclical error occurs with `returnKey`: + +1. Pressing the return key, when login is enabled, should put the system in a logging in state. +2. When the system is in a logging in state, the login button should be disabled. +3. When login is disabled, the return key should no longer work. + +The dependency chain for this looks like: +`returnKey -> loggingIn behavior -> loggingIn -> loginEnabled behavior -> loginEnabled -> loggingIn behavior (cycle)` + +Our solution is to recognize that when pressing the return key, the system is not interested in what state `loginEnabled` will enter during that event, but what it was as the event begins. + +* Pressing the return key should not try to log the user in again if loginEnabled is {false-bool}. +* If it is {true-bool} then the user can log in at which point it will become {false-bool}. +==== + +== Fixing Problems + +=== State resources have trace values + +Use trace values to break cycles. + +Calling `traceValue` on a state resource inside a behavior will return its contents as they are at the beginning of the event. +If at some point during the same event the contents change from an update, the `traceValue` will continue to return the value that it was before that update. + +Accessing the `traceValue` of a resource does not require it to be listed in the demands list of the behavior. + +It is important to remember that `traceValue` is different than the prior value. +It is only the prior value if it updated during this event. +After the event ends, `traceValue` and `value` will return the same contents. + +==== + +[source, {source-language}, numbered, indent=0] +.Logging in behavior +---- +include::{sourcedir}/{example-loginextent}[tags=login_complete_login] +---- + +{source-tracevalue-1} accesses `loginEnabled.traceValue` to prevent a potential cycle. +It is not listed in the demands and Behavior Graph will not throw an error. + +The behavior graph diagram in <> renders the dependency between `loginEnabled` and the behavior that supplies `loggingIn` with a dotted line to show the connection. +==== + +In Behavior Graph diagrams, trace value dependencies are drawn as a dotted line and point to the lower portion of the behavior to visually separate them from other dependencies. + +=== Use the debug console to track down cycles + +Cycles that span many behaviors and extents are not always obvious. +The console will print the sequence of behaviors and resources that create the cycle. +Use this information to help determine where the chain can be broken. + +You can call `cycleStringForBehavior` on the instance of the {graph-class} to print or step through these objects. + +=== Complex behaviors can make it easier to create cycles + +TIP: Combining many different demands and supplies in the same behavior can be practical and sometimes necessary. +However, these behaviors also make it easier to create graph cycles during the development phase. +Separating out independent functionality into different behaviors can often free up cycles. + +=== Side effect blocks run after all behaviors + +Behaviors may create side effects. +By design, those side effects do not run until there are no more activated behaviors in the queue, ie the end of the event. + +==== +[source, {source-language}, numbered, indent=0] +[[login_complete_enable]] +.Login Enable +---- +include::{sourcedir}/{example-loginextent}[tags=login_complete_enable] +---- + +As can be seen from the <> diagram, this behavior has no downstream dependencies and will be the last to be run. +{source-sideeffect-1} creates a side effect which will not be run until after this behavior completes. + +Likewise when the user clicks the login button the first time, the side effect on {source-sideeffect-2} of <> will also not be run until this behavior completes. + +==== + +The reason for postponing the running of side effects is to ensure that unstable information doesn't leak out into the environment. +As a side effect block runs, Behavior Graph must relinquish control flow. +That code may call out to some external library which subsequently calls back in to read the current value of a resource. +If we were in the behavior phase of an event, any number of resources may still need updating to new values. +The resources in the system are only in a stable state after all activated behaviors have been run. + +=== Side effect blocks are run in the order they are created + +Most systems will need some ability to maintain sequential dependencies between the code run in side effects. +For example one behavior may create the side effect for initializing a video player. +A separate behavior may create a side effect which tells the video player to play. +It is necessary to ensure the video player is created before it is told to play. + +==== +In <>, the login call will be made before the button is disabled when the user clicks the login button. +This is because the two behaviors that create those side effects will be run in that order. +==== + +If your code has implicit dependencies between side effect blocks, you can make them explicit by creating a dependency between their creating behaviors. +Do this by creating a resource which is supplied by the behavior that creates the first side effect and demanded by the behavior that creates the second side effect. + +=== Events are serialized + +It is possible for an action to be created while another event is currently executing when a side effect block leads to a new action and there are still side effects remaining. +However, interrupting the current event to run another one could lead to inconsistent results. +It is necessary for the entire event to work as a single transaction. + +When this happens: + +1. The new action will be placed in a queue and the current event will continue to run any remaining side effects of current event at the action creation point. +2. When the current event completes, the newly queued up action will create an event and run until completion. +3. This will continue until there are no more queued actions, at which point the code will continue. + +==== +[source, {source-language}, numbered, indent=0] +.Logging in behavior +---- +include::{sourcedir}/{example-loginextent}[tags=login_complete_login] +---- +1. When the user clicks the login button, this behavior that logs the user in will activate and run. +2. {source-serialize-1} will be run during the side effect phase of the event. +3. It is possible this external `login` method may immediately call the completion block which will then create a new action on {source-serialize-2}. +4. The first event created by clicking the login button is still running. It needs to complete before running this new login complete action. So it will place the login complete action in the queue and continue to its next side effect which will disable the login button. +5. After running the remaining side effect, the first event will complete, and the code inside the action block created on {source-serialize-2} will run. +6. This new event will run to completion. +7. Finally the stack from the initial side effect created on {source-serialize-3} will complete and unwind. +==== + +=== Events are synchronized onto the same thread + +Behavior Graph does not handle concurrency. +All events are serialized onto the same thread which can be specified when initializing the `{graph-class}` object. + +=== Actions blocks are run synchronously + +When the environment creates a new action, that action block and the entire event will be run synchronously. +The line of code that follows the action will not be run until the event created by that action has run to completion. + +This default matches imperative programming expectations. +If a line of code following the action block attempts to read the value of a resource, you can expect it to have been updated accordingly. +And all side effect blocks created as a result of that action will be run before that next line of code. + +As mentioned previously, however, there may already be a running event or queued actions when a new action is created. +Many events may get run between the time an action is created and when its own corresponding event is run. +These events will all run to completion before the code that creates the action returns. + +==== +[source, {source-language}, numbered, indent=0] +.Login click +---- +include::{sourcedir}/{example-loginpage}[tags=login_complete_click] +---- +This method creates a new action on line 2; however, we cannot guarantee that the code inside the action is run immediately. +The Behavior Graph does guarantee that all events will have completed before proceeding past line 4 and exiting this method. +==== + +=== Side effects can't be strictly enforced + +You should always create a side effect when you wish to output information to the environment. +However, strictly enforcing this policy would require wrapping every possible type of output. + +Instead, the code in behavior blocks is normal imperative code. +Technically anything is possible. +In order to manage control flow, the Behavior Graph cannot handle a new synchronous action while still running behaviors during an event. + +If, from inside a behavior (not side effect), you create a synchronous action or call some code that eventually leads to a synchronous action, Behavior Graph will raise an error. + +Also, if, from inside a behavior (not side effect), you call some code that eventually leads to accessing a non-demanded resource, Behavior Graph will raise an error. + +Instances of this error can be subtle. +Be careful when working with anything that may affect the environment directly from a behavior. +This includes memory allocation, destructors, exceptions, or any other impure code. + +=== Action blocks can have optional synchrony (but not the default) + +The safest way to create a new action is to opt out of synchrony. +To do this call `{asyncaction-method}`. + +This method of creating a new action will run the action and associated event immediately if there are no events running currently. +Otherwise, it will put them on a queue to be run after the current event (and any additional queued actions) are run, returning up the call stack. + +Prefer this variation whenever possible. + +==== +A better implementation of the login side effect in <> would opt out of synchrony. + +[source, {source-language}, numbered, indent=0] +---- +include::{sourcedir}/{example-loginextent}[tags=login_complete_loginalt] +---- + +{source-async} uses the optional asynchronous form when creating a new action. +Opting out of synchrony here means the side effect created on line 1 will exit its call stack before starting the event associated with this new action. +==== + +=== Events have sequence numbers + +When a resource is updated it retains a reference to the instance of `{event-class}` in which it was last updated. +These event instances have a monotonically increasing sequence number (every event run is +1 the prior event). +You can use these sequence numbers to compare multiple resources to determine the order they were updated. + +If this `event` property is accessed inside a behavior its resource must be declared as a demand. +There is a corresponding `traceEvent` available if such a dependency creates a cycle. +==== + +We can compare the timestamps of the `password` and `email` resources to see if one were updated more recently. + +[source, {source-language}, numbered, indent=0] +---- +include::{sourcedir}/{example-loginextent}[tags=login_sequence_compare] +---- + +==== + +=== Events have timestamps + +Each event also gets a timestamp when the event is run. + +It is a common programing idiom to interweave code with timestamp parameters in order to facilitate testing and instrumentation. +By providing this information as part of each event, behaviors and side effects have easy access without the typical crosscutting burden. + +==== +We can reference when the login happened in some security auditing code. + +[source, {source-language}, numbered, indent=0] +---- +include::{sourcedir}/{example-loginextent}[tags=login_timestamp] +---- +==== + +For testing purposes you can mock out the date provider of the graph object in one place. +Override the `{dateprovider-property}` property with your own implementation of {dateprovider-class}. + +== Architecting Systems + +=== Video Chat Example + +We will now change our example app to a hypothetical but familiar video chat experience. + +[[video_chat, Video chat]] +.Video chat +==== +image::video_chat_ui.png[Video chat] + +* There will be a grid of squares showing the live video feed for a number of participants. +* Each participant will have a small button overlay for toggling their mute. +* Each participant will have a small button overlay to pin that participant. +* When a participant is pinned, that ui will appear larger than the others. +* Only one participant can be pinned at the same time. +If there is already a pinned participant, tapping on the pin button of another will unpin the first and pin the new one. + +The Behavior Graph diagram for this functionality looks like this + +image::video_chat_diagram.png[Video Chat Diagram] + +==== + +=== Extents capture lifetimes + +Extents can come and go, reflecting the range of time they play a useful role in your system. + +==== +In the <> example, we will have two types of extents. + +A single `ChatExtent` will be created and added to the graph every time we initiate a new chat. +It reflects the lifetime of the video chat. +Once the chat is over, it no longer plays a functioning roll and can be removed from the graph. + +[source, {source-language}, numbered, indent=0] +---- +include::{sourcedir}/{example-chat-chat-header}[tags=chat_extent] +---- + +A `ParticipantExtent` will be created each time a new participant joins the video chat. +Each chat may have multiple participants. +They may come and go at any time during the video chat. + +[source, {source-language}, numbered, indent=0] +---- +include::{sourcedir}/{example-chat-participant-header}[tags=participant_extent] +---- + +==== + +=== Extents exclusively own behaviors and resources + +Behaviors and resources always belong to one and only one extent. + +They do not exist independently from their owning extent. + +You cannot create a resource on one extent and assign it to a member variable on another. + +=== Resources are named and assigned to extent member variables + +You will regularly refer to resources by name via their extent. + +==== +Our mute functionality requires some resources which we declare as properties on the ParticipantExtent. + +[source, {source-language}, numbered, indent=0] +---- +include::{sourcedir}/{example-chat-participant-header}[tags=participant_mute_resources] +---- + +* `muteTap` is a moment resource that tracks the user tapping on the mute button. +* `muted` is a state resource that captures the local muted status of that participant. +ifeval::["{bg-doc-version}" == "objc"] +It is an `NSNumber` to store our Objective-C boxed boolean. +endif::[] + +We will initialize and assign them in the constructor along with the behavior that links to them. + +[source, {source-language}, numbered, indent=0] +[[participant_mute]] +.Mute behavior +---- +include::{sourcedir}/{example-chat-participant}[tags=participant_mute] +---- + +On line 3 we refer to their member variables directly when specifying the linked resources for this behavior. +On almost every line thereafter we refer to them by name via their extent. + +==== + +=== Behaviors are typically unnamed + +Initialize behaviors via the `{extent-class}` factory method `{behavior-method}`. + +Behaviors can have their linked resources redefined dynamically. +You can optionally save the results of that method to a member variable if you wish to do this. + +==== +[source, {source-language}, numbered, indent=0] +---- +include::{sourcedir}/{example-chat-participant}[tags=participant_mute_alt] +---- +==== + +=== Behaviors and resources are added to and removed from a graph via extents + +Add behaviors and resources to the graph by adding their owning extent. +Use the `{addtograph-method}` method of the extent object. + +Adding and removing extents must happen during an event– either inside an action or behavior. +Doing otherwise will raise an error. + +Behaviors which have not yet been added to the graph will not run. +Updating a resource which has not yet been added to the graph will raise an error. + +==== + +During a video chat, our system will need to handle participants joining and leaving. +We will model this by adding and removing instances of `ParticipantExtent` to the graph. + +To capture this functionality, we will have a behavior that demands resources indicating that a participant has joined or left. +When these moments happen our behavior can either create and add the new extent or remove the old one. + +[source, {source-language}, numbered, indent=0] +[[participants_add]] +.Add participants +---- +include::{sourcedir}/{example-chat-chat}[tags=participants] +---- + +Each time a new participant joins our video chat, the moment resource `participantJoined` will update, activating this behavior. +In response we will create a new instance of `ParticipantExtent` on {source-addtograph-1}. +We add it to the graph on the next line. + +If the participant later disconnects we can remove it's functionality from the graph. +{source-addtograph-2} removes it from the graph. + +==== + +Once an extent has been removed from the graph its elements will be removed and unlinked from any other elements still in the graph. +A removed behavior will no longer activate in response to resources it demanded. +A removed resource will no longer activate behaviors and updating it will result in an error. + +=== Behaviors always activate in the same event that their extent is added to a graph + +When programming a behavior it is important to remember that it will get run at this time. +Use this to set initial values on state resources when information is not available at initialization time. + +ifeval::["{bg-doc-version}" == "objc"] +endif::[] + +=== Extents are the execution context for behaviors and sideEffects + +Extents are reference objects. +They enable code inside behaviors and side effects to interact with other graph elements or the environment. +The extent parameter passed into behaviors and side effects is this point of reference. + +NOTE: Most object oriented languages predefine `self` or `this` to serve a similar role inside methods. + +==== +[source, {source-language}, numbered, indent=0] +.Mute behavior +---- +include::{sourcedir}/{example-chat-participant}[tags=participant_mute] +---- + +Here we can see nearly every single line in both the behavior and the side effect utilize their `extent` parameter to refer to resources and call methods. +==== + +=== Resources and behaviors can link across extents + +Frequently information stored in a resource will outlive the behaviors that react to changes in that information. +To enable this, a behavior can demand or supply resources from extents different from their owning extent. + +==== +In our <>, pinning one participant means unpinning the previous one if available. +The resource which can track which participant is currently pinned must outlive any particular participant. + +The central `ChatExtent` has a resource `pinnedParticipant` that stores a reference to the currently pinned `ParticipantExtent`. +Each `ParticipantExtent` instance has a behavior that demands that resource. + +[source, {source-language}, numbered, indent=0] +---- +include::{sourcedir}/{example-chat-participant}[tags=participant_pinned] +---- +* Line 1 demands the common `pinnedParticipant` on the `ChatExtent` instance stored in the member variable `chatExtent`. +* We wish for the UI to draw the pinned participant larger than the others. +The first clause of the if statement, checks to see if the `pinnedParticipant` became this extent and creates a side effect to enact that change. +* The second clause checks if the pinned participant is no longer this extent, returning it to normal size. + +Because each `ParticipantExtent` instance demands this central resource, updating that one resource will automatically cause this behavior in each participant to update its respective UI during the same event. +==== + +=== Store related extents in a collection resource + +Many applications naturally organize into a hierarchy of lifetimes. +These different lifetimes should be modeled with extents. + +The parent extent should own a state resource containing a collection of child extents. + +==== +[source, {source-language}, numbered, indent=0] +.Add participants +---- +include::{sourcedir}/{example-chat-chat}[tags=participants] +---- + +In our <>, the lifetime of each participant is necessarily bounded by the lifetime of the entire chat. + +On our `ChatExtent` we create a `participants` resource to hold on to them. +This state resource holds a dictionary which maps a participant id string to each participant extent. + +[source, {source-language}, numbered, indent=0] +---- +include::{sourcedir}/{example-chat-chat-header}[tags=chat_participants_resources] +---- + +In the behavior that supplies this resource, we update it any time a participant joins or disconnects. + +It is worth noting how we update the `participants` resource in this behavior. + +1. On {source-extentcollections-1} we directly manipulate the stored dictionary. +2. On the following lines {source-extentcollections-2}, we update using the same dictionary instance and skipping the equality check. +By skipping this equality check, we activate any behaviors which demand the resource while also keeping the same collection. +If we did not skip the equality check, the state resource would recognize that the collection was the same instance and make no update. + +==== + +=== Relink behaviors dynamically + +Behaviors may link to resources in other extents. +Those extents may come and go. +Therefore it is necessary to change their links separately from when those behaviors were initialized and added to the graph. + +You may call `setDemands` and `setSupplies` on a behavior to change those links. +Once that behavior has been added to the graph, you can only call those methods from inside an action or behavior block. + +It is an error to modify a behavior's links during an event if that behavior has already run during that event. +To prevent this, the behavior that modifies the links should supply a special resource which the Behavior Graph will use for proper ordering. +The behavior which has its links modified should demand this ordering resource. + +==== +To fully implement our pinning functionality, there will be a `pinTap` moment resource on each `ParticipantExtent`. + +[source, {source-language}, numbered, indent=0] +---- +include::{sourcedir}/{example-chat-participant-header}[tags=participant_pin_resources] +---- + +There will also be a behavior in the `ChatExtent` to decide which participant should be pinned. +This behavior demands the `pinTap` in each `ParticipantExtent` in order to be activated whenever any of those resources is updated. +However, because participants can come and go, we will not have access to all of these resources at initialization time. +So we will leave them out initially in the demands list when we define our pinned behavior. + +[source, {source-language}, numbered, indent=0] +[[chat_pinned]] +.Pinned Behavior +---- +include::{sourcedir}/{example-chat-chat}[tags=chat_pinned] +---- + +* On {source-dynamic-1}, we iterate through each `ParticipantExtent` instance in the `participants` resource. +* The next lines inspect the `pinTap` resource on each extent to determine if the user tapped on one or if it should maintain the current pinned participant. + +At this point however, the behavior will not get run when a pinTap resource is updated. +Additionally it will be an error for it to access the `pinTap` resources because it does not demand them. +We will introduce an additional behavior which updates these demands as the participants change. + +[source, {source-language}, numbered, indent=0] +---- +include::{sourcedir}/{example-chat-chat}[tags=chat_relink_pinned] +---- + +Each time a new participant is added or removed (updating the `participants` resource), this behavior will activate and update the demands of <>. + +* On {source-dynamic-2}, `participants` and `participantsRelink` are added to the array. +They are added because they are part of the default list of demands when <> was initialized. +* Next we iterate through each `ParticipantExtent` instance and add its `pinTap` resource to the array. +* Lastly {source-dynamic-3} updates the demands of that behavior. + +Note the use of `participantsRelink` resource. +It is of the base type `{resource-class}` which has limited functionality. +This is our ordering resource. +It has no value and is not updated. +It only exists to ensure that the demands of the `pinnedBehavior` are updated before the behavior itself is run. +==== + +=== Supplies can also be relinked dynamically + +It is less useful in practice. +Occasionally you may wish to have the behavior on one of many child extents update a resource on the parent level. +As these extents come and go, you may need to designate a new supplier. + +=== Updating links will cause dependent behaviors to activate + +When the demands of a behavior change, that behavior is activated and run to ensure it is fully taking into account its current set of demands. + +When a resource is supplied by a new behavior any behaviors that demand that resource will activate. + +=== Removed resources and behaviors are automatically removed from demands and supplies + +Whenever an extent is removed from the graph all its resources and behaviors will also be removed. +Any remaining resources and behaviors will have their links to the removed elements severed. + +=== Removed behaviors will not run in the event they are removed + +If an activated behavior is removed before it is run, it will not be run. + +=== A program may have multiple instances of a graph + +A program or library can have any number of independent instances of a {graph-class}. +Behaviors and resources cannot link across graph instances. +Extents cannot migrate between graph instances. + +=== Independent graphs may communicate through message passing + +One graph may pass information to another by creating a side effect on one which creates a new action on the other. diff --git a/doc-site/content/en/ignore/includes.adoc b/doc-site/content/en/ignore/includes.adoc new file mode 100644 index 0000000..d36deef --- /dev/null +++ b/doc-site/content/en/ignore/includes.adoc @@ -0,0 +1,172 @@ +tag::objc[] +:sourcedir: ./examples/objc/BGExamples +:source-language: objectivec +:false-bool: @NO +:true-bool: @YES +:resource-class: BGResource +:state-class: BGState +:moment-class: BGMoment +:extent-class: BGExtent +:graph-class: BGGraph +:event-class: BGEvent +:action-method: action +:sideeffect-method: sideEffect: +:addtograph-method: addToGraph +:behavior-method: behaviorWithDemands: +:update-method: updateValue: +:momentupdate-method: update +:momentjustupdated-method: justUpdated +:statejustupdated-method: justUpdated +:statejustupdatedto-method: justUpdatedTo: +:statejustupdatedtofrom-method: justUpdatedTo:from: +:asyncaction-method: action:requireSync:NO +:dateprovider-property: dateProvider +:dateprovider-class: BGDateProvider +:example-loginextent: LoginExtent.m +:example-loginextent-header: LoginExtent.h +:example-loginpage: LoginPageViewController.m +:example-chat-chat: ChatExtent.m +:example-chat-chat-header: ChatExtent.h +:example-chat-participant: ParticipantExtent.m +:example-chat-participant-header: ParticipantExtent.h +:constructor: initializer +:string-class: NSString +:source-resource-1: Lines 5 and 6 +:source-sideeffect-1: Line 9 +:source-statemanagement-1: Line 8 +:source-justupdated-1: Line 11 +:source-justupdated-2: Line 18 +:source-tracevalue-1: Line 9 +:source-sideeffect-1: Line 10 +:source-sideeffect-2: line 20 +:source-serialize-1: Line 21 +:source-serialize-2: line 23 +:source-serialize-3: line 19 +:source-async: Line 4 +:source-addtograph-1: line 9 +:source-addtograph-2: Line 19 +:source-extentcollections-1: lines 12 and 20 +:source-extentcollections-2: lines 13 and 21 +:source-dynamic-1: line 8 +:source-dynamic-2: lines 5 and 6 +:source-dynamic-3: line 10 +:uses-crtp: +:readme-doc: readme-objc.html +:guide-doc: objc.html +:github-project: bgobjc +end::objc[] + +tag::typescript[] +:sourcedir: ./examples/typescript/BGExamples +:source-language: typescript +:false-bool: false +:true-bool: true +:resource-class: Resource +:state-class: State +:moment-class: Moment +:extent-class: Extent +:graph-class: Graph +:event-class: GraphEvent +:action-method: action +:sideeffect-method: sideEffect +:addtograph-method: addToGraph +:behavior-method: makeBehavior +:update-method: update +:momentupdate-method: update +:momentjustupdated-method: justUpdated +:statejustupdated-method: justUpdated +:statejustupdatedto-method: justUpdatedTo +:statejustupdatedtofrom-method: justUpdatedToFrom +:asyncaction-method: actionAsync +:dateprovider-property: dateProvider +:dateprovider-class: BehaviorGraphDateProvider +:example-loginextent: LoginExtent.ts +:example-loginextent-header: LoginExtent.ts +:example-loginpage: LoginExtent.ts +:example-chat-chat: ChatExample.ts +:example-chat-chat-header: ChatExample.ts +:example-chat-participant: ChatExample.ts +:example-chat-participant-header: ChatExample.ts +:constructor: constructor +:string-class: string +:source-resource-1: Lines 2 and 3 +:source-sideeffect-1: Line 6 +:source-statemanagement-1: Line 5 +:source-justupdated-1: Line 9 +:source-justupdated-2: Line 17 +:source-tracevalue-1: Line 7 +:source-sideeffect-1: Line 7 +:source-sideeffect-2: line 18 +:source-serialize-1: Line 19 +:source-serialize-2: line 21 +:source-serialize-3: line 18 +:source-async: Line 3 +:source-addtograph-1: line 8 +:source-addtograph-2: Line 17 +:source-extentcollections-1: lines 10 and 18 +:source-extentcollections-2: lines 11 and 19 +:source-dynamic-1: line 6 +:source-dynamic-2: lines 4 and 5 +:source-dynamic-3: line 9 +:readme-doc: readme-typescript.html +:guide-doc: typescript.html +:github-project: bgjs +end::typescript[] + +tag::kotlin[] +:sourcedir: ./examples/kotlin/BGExamples +:source-language: kotlin +:false-bool: false +:true-bool: true +:resource-class: Resource +:state-class: State +:moment-class: Moment +:extent-class: Extent +:graph-class: Graph +:event-class: GraphEvent +:action-method: action +:sideeffect-method: sideEffect +:addtograph-method: addToGraph +:behavior-method: makeBehavior +:update-method: update +:momentupdate-method: update +:momentjustupdated-method: justUpdated +:statejustupdated-method: justUpdated +:statejustupdatedto-method: justUpdatedTo +:statejustupdatedtofrom-method: justUpdatedToFrom +:asyncaction-method: actionAsync +:dateprovider-property: dateProvider +:dateprovider-class: BehaviorGraphDateProvider +:example-loginextent: LoginExtent.kt +:example-loginextent-header: LoginExtent.kt +:example-loginpage: LoginExtent.kt +:example-chat-chat: ChatExample.kt +:example-chat-chat-header: ChatExample.kt +:example-chat-participant: ChatExample.kt +:example-chat-participant-header: ChatExample.kt +:constructor: init +:string-class: String +:source-resource-1: Lines 2 and 3 +:source-sideeffect-1: Line 6 +:source-statemanagement-1: Line 5 +:source-justupdated-1: Line 9 +:source-justupdated-2: Line 17 +:source-tracevalue-1: Line 7 +:source-sideeffect-1: Line 7 +:source-sideeffect-2: line 18 +:source-serialize-1: Line 19 +:source-serialize-2: line 21 +:source-serialize-3: line 18 +:source-async: Line 3 +:source-addtograph-1: line 8 +:source-addtograph-2: Line 17 +:source-extentcollections-1: lines 10 and 18 +:source-extentcollections-2: lines 11 and 19 +:source-dynamic-1: line 6 +:source-dynamic-2: lines 4 and 5 +:source-dynamic-3: line 9 +:uses-crtp: +:readme-doc: readme-kotlin.html +:guide-doc: kotlin.html +:github-project: bgkotlin +end::kotlin[] diff --git a/doc-site/content/en/ignore/intro.adoc b/doc-site/content/en/ignore/intro.adoc new file mode 100644 index 0000000..398d6b1 --- /dev/null +++ b/doc-site/content/en/ignore/intro.adoc @@ -0,0 +1,273 @@ +--- +title: "Intro" +--- + += Behavior Graph +:icons: font +:imagesdir: /images +:sectlinks: +:source-highlighter: rouge +:rouge-theme: molokai +:toc: left +//:bg-doc-version: objc +:bg-doc-version: typescript +:github-root: https://github.com/yahoo/ +:pages-root: https://yahoo.github.io/bgdocs/docs/ +include::content/en/includes.adoc[tag={bg-doc-version}] + +== Links +* link:{github-root}{github-project}[Github] +* link:{pages-root}{bg-doc-version}/intro.html[Intro (this document)] +* link:{pages-root}{bg-doc-version}/guide.html[Behavior Graph Programming Guide] +ifeval::["{bg-doc-version}" == "objc"] +* *Cocoapods* (Objective-C): BehaviorGraph +endif::[] +ifeval::["{bg-doc-version}" == "typescript"] +* *NPM* link:https://www.npmjs.com/package/behavior-graph[`behavior-graph`] +* *jsDelivr* https://cdn.jsdelivr.net/npm/behavior-graph/lib/behavior-graph.min.js +endif::[] + +ifeval::["{bg-doc-version}" == "kotlin"] +??? +endif::[] + + +== Safe Mutable State + +**Behavior Graph** is a software library that greatly enhances our ability to program **user facing software** and **control systems**. +Programs of this type quickly scale up in complexity as features are added. Behavior Graph directly addresses this complexity by shifting more of the burden to the computer. +It works by offering the programmer a new unit of code organization called a **behavior**. +Behaviors are blocks of code enriched with additional information about their stateful relationships. +Using this information, Behavior Graph enforces _safe use of mutable state_, arguably the primary source of complexity in this class of software. +It does this by taking on the responsibility of control flow between behaviors, ensuring they are are _run at the correct time and in the correct order_. + +=== State + +It helps to understand why user facing software, control systems, and similar programs present a particular challenge. + +We define these systems by three primary characteristics: + +1. *Asynchronous*: inputs happen over a period of time +2. *Event-driven*: outputs occur over time in response to inputs +3. *Stateful*: outputs depend on a history of prior inputs + +A thermostat controlling the temperature in a house is an example: + +image::thermostat-wall.svg[Login page] + +1. It runs continuously, responding to temperature changes as well as button presses in order to operate the heating equipment. +2. Button presses will result in changes to the display. +3. Button presses which set the desired temperature will determine when the heating equipment turns on in the future. + +The challenge comes from the large number of different inputs where order and history matter. +A sequence of 10 presses on our Up and Down buttons can occur in over 1000 different ways. +An interface that accepts 10 different types of input over a sequence of 10 events means we are facing 10 billion possible arrangements. +And that is a tiny fraction of what a real user facing application is typically up against. + +The solution comes from the fact that we only need to remember just enough information to make decisions in the future. +Instead of remembering each button press, we simply remember a desired temperature and update it as inputs happen. +We don't care which sequence of button presses gets us to 68 degrees. +To our program they are all the same. +We call this compressed historical information *state.* +With state we can compress 10 billion button presses into a single number. + +Inputs lead to state changes. +Pressing the Up and Down button changes the desired temperature state. +State changes lead to outputs. +Changing the desired temperature means the disply will change. +State changes also often lead to other state changes as our program grows in features. +When the desired temperature changes, the desired state of the heating equipment may change. +(And when that desired state of the heating equipment changes, our program will output to turn on or off the heating equipment.) + +A correctly functioning program will have a natural dependency graph between inputs, internal states, and outputs. +Unfortunately, status quo programming techniques have no way of expressing this dependency graph directly. +Programmers must implicitly build this graph out of the correct sequencing of method calls and state updates. +In so doing, they throw away this valuable dependency information and the computer can no longer help us. +**That is the root of the problem.** + +=== Behavior Graph + +With Behavior Graph, we build our programs out of units of functionality called *behaviors*. +Behaviors manage state via components called *resources*. +Behaviors are simple, easily understood blocks of code paired with any relationships to these resources. +Resources are objects which encapsulate both state and how that state changes. +A behavior for our thermostat would be "_when the user presses the *Up* or *Down* buttons, increase or decrease the desired temperature by one degree_." +The _desired temperature_ is the resource that this behavior manages. + +image::thermostat-temp.svg[Login page] + +An entire thermostat program would be built out of many of these behaviors. +So we add a second behavior, "_when the current temperature is below the desired temperature, turn on the heating equipment_." +Our behaviors will collaborate to implement the complete thermostat functionality without knowing about each other directly. +Instead, behaviors compose via resources, in this case _desired temperature_. +The first behavior declares that it is responsible for setting the _desired temperature_. +The second behavior declares that it uses the _desired temperature_ to know if it needs to turn on the heat. + +image::thermostat-heat.svg[Login page] + +We never run behaviors directly by calling them like we do with methods. +Instead Behavior Graph uses the dependencies between behaviors and resources to determine which behaviors need to run and in which order. +If the user presses the Up button to raise the desired temperature above the current temperature, the heating behavior will automatically run after the temperature behavior updates the _desired temperature_ resource. + +Here we can see the contrast to the status quo approach of nesting chains of method calls. +In order to ensure the heat can be turned on when the up button is presset, the button press method needs to call the desired temperature setting method. +And that method in turn needs to call the heating equipment method. +Because no method runs unless another method calls it, we must explicitly weave these threads of control flow throughout our code. +In large programs, separately maintaining control flow to ensure our dependency graph is respected is both difficult and error prone. + +Fred Brooks link:https://en.wikipedia.org/wiki/No_Silver_Bullet[famously pointed out] that software is necessarily complex because the problems themselves are complex. +With Behavior Graph we overcome our human complexity limits by delegating more of that work to the computer itself. +As programmers, we focus on individual behaviors and their immediate relationships. +The computer in turn handles the complex chore of sorting through hundreds or thousands of those behaviors to ensure a working program. + +Behavior Graph gives us control flow for free. + +Behavior Graph is a compact and mature library with no external dependencies. +It is used in production applications with millions of daily users. +It is available for multiple languages and platforms (Objective C/Swift, Typescript/Ja*vascript, Kotlin). + +== Walkthrough + +We can illustrate how Behavior Graph code works in detail through another example application, a typical login screen. + +image::login-ui-2.svg[Login page] + +As a first feature, we would like the Login button to remain disabled until the user has entered both a reasonable email and password. +If the user types in some password but an invalid email address (missing the '@' character, for example) the Login button will remain disabled. +Once she corrects the email address by adding an '@' character, the Login button should immediately enable. + +In Behavior Graph, this unit of functionality constitutes a typical *behavior*. +It looks like this + +[source, {source-language}, numbered, indent=0] +---- +include::{sourcedir}/{example-loginextent}[tags=login_intro_short1] +---- + +Behaviors have dependencies on units of information called *resources*. +This behavior depends on two resources, `email` and `password`. +They appear as a list in the first parameter to `makeBehavior`. +This list is called the behavior's *demands*. +Our behavior has read only access to these resources. + +As stated before, behaviors are never called directly. +In specifying a behavior's demands, we are saying, _"whenever any of these resources updates (changes), then this behavior needs to run"._ +In our example, when either `email` or `password` (or both) update, this behavior will run in response. + +`email` and `password` are a specific type of resource called a *state resource* which is designed for saving and retreiving information. +The contents of these state resources is available via their `value` property. + +The block of code specified in the behavior is the code that will run. +A typical behavior uses normal code to perform its work. +Here we check the validity of the email with a normal function. +We determine if the Login button should be enabled using normal boolean logic. + +This behavior is responsible for the enabled state of the Login button. +This information is stored in another state resource called `loginEnabled`. +We specify a behavior's responsibilites as a list in the second parameter to `makeBehavior`. +This list is called the behavior's *supplies*. +A behavior can read and write the contents of its supplies. +The contents of a state resource can be written to by calling its `{update-method}` method. + +We can continue to develop our Login page by adding a second feature. +When the user clicks the Login button and we are not already logging in, then we would like to enter into a logging in state. +In order to prevent mistakes, when we are in a logging in state, we would also like the Login button to be disabled. + +To implement this new feature we introduce a second behavior and make a small change to our existing behavior. + +[source, {source-language}, numbered, indent=0] +---- +include::{sourcedir}/{example-loginextent}[tags=login_intro_short2] +---- + +The new behavior has one demand, `loginClick`. +This is a second type of resource called a *moment resource*. +Moments are designed to track momentary happenings such as a button click or network call returning. +We can check if a moment has just happened by accessing its `{momentjustupdated-method}` property. + +When the user clicks on the button, `loginClick` will update, and this new behavior will run. +It performs a simple boolean check to determine if the `loggingIn` state resource needs to update to `{true-bool}`. +It is allowed to update this resource because `loggingIn` is part of its supplies. + +We also modified our previous behavior to include `loggingIn` as one of its demands. +This means it will run when the `loggingIn` resource updates as well as have permission to access the boolean `value` of `loggingIn`. +Now the state of `loginEnabled` depends on all three pieces of information: `email`, `password`, and `loggingIn`. + +image::login-intro-graph.svg[Login Behavior Graph] + + +Information comes into our system via *actions*. +A typical UI library will provide some type of callback or event system to capture user inputs. +In this example we will listen to a click handler to create a new action which updates the `loginClick` moment resource. + +[source, {source-language}, numbered, indent=0] +---- +include::{sourcedir}/{example-loginextent}[tags=login_intro_action] +---- + +We would similarly connect `email` and `password` to their respective text fields. + +Once the user has entered a valid email and password, the Login button will enable. +When the user subsequently clicks on the Login button, the behavior that supplies `loggingIn` will run. +It will update the `loggingIn` resource to `{true-bool}`. +This in turn will cause the behavior that supplies `loginEnabled` behavior to run. +It will update the `loginEnabled` resource to `{false-bool}`. + +In order to perform real output to the UI library, we need to create a *side effect*. + +[source, {source-language}, numbered, indent=0] +---- +include::{sourcedir}/{example-loginextent}[tags=login_intro_sideeffect] +---- + +Side effects are created directly inside behaviors. +This side effect updates the `enabled` state of the `loginButton` based on the state of the `loginEnabled` resource. +It does not run immediately, however. +Behavior Graph defers the running of side effects until after all behaviors have run. +Side effects are a practical way for Behavior Graph to create output while ensuring access to consistent state. + +This example covers the primary concepts when developing with Behavior Graph. +There are, however, additional features that make Behavior Graph a practical software library. +link:https://{guide-doc}[The Programming Guide] explains these features in detail. + +== Reactive Programming + +Behavior Graph graph has many characteristics of a link:https://en.wikipedia.org/wiki/Reactive_programming[reactive programming] library. +If you are familiar with other libraries in this family you should find some similarities. +There are some important distinctions: + +* Behaviors function as _observers_ and resources function as _observables_. +They are always separate objects, however. +* It is not based on streams. +* It does not use a link:http://reactivex.io/documentation/operators.html[large library of functional combinators]. +* The principles are not programming language or platform specific. +* It does not have link:https://en.wikipedia.org/wiki/Reactive_programming#Glitches[glitches]. +* It does not permit link:https://en.wikipedia.org/wiki/Reactive_programming#Cyclic_dependencies[cyclic dependencies] and provides tools for discovering and avoiding them. +* It is a dynamic dataflow graph. Relationships between behaviors and resources can change at runtime which enables powerful modeling techniques. + +== Related Work + +* link:https://en.wikipedia.org/wiki/Cybernetics[Cybernetics] describes the "closed signaling loop", the essence of Unidirectional Data Flow architectures (aka MVI or Model View Intent). +* link:https://redux.js.org[Redux] (and Flux) are popular Javscript state management frameworks organized around Unidirectional Data Flow. There are similar implementations for different platforms, eg link:https://github.com/day8/re-frame[re-frame/Clojure]. +* link:https://en.wikipedia.org/wiki/Functional_reactive_programming[Functional Reactive Programming] (FRP) is not new. +* link:http://reactivex.io[ReactiveX] is a popular reactive programming implementation for many different imerative languages. * link:https://github.com/spotify/mobius[Mobius] is another take on FRP and Unidirectional Data Flow for the Android platform. +* link:https://en.wikipedia.org/wiki/Observer_pattern[Observers] aren't new. +* link:https://cycle.js.org[Cycle.js] Javascript reactive library. +* link:https://mobx.js.org/README.html[MobX] Javascript reactive library. +* link:https://www.rescala-lang.com[REScala]. +* link:https://developer.apple.com/documentation/combine[Apple's Combine]. +* link:https://docs.oracle.com/javase/9/docs/api/java/util/concurrent/Flow.html[Java Flow]. +* link:http://www.inf.ed.ac.uk/teaching/courses/seoc/2005_2006/resources/statecharts.pdf[State Charts(pdf)]. +* link:https://xstate.js.org[X State], state chart library. +* link:https://en.wikipedia.org/wiki/Publish–subscribe_pattern[Event Bus/Pub-Sub] is a pattern for building reactive style architectures. +* link:https://elm-lang.org[Elm], a functional programming language with reactive principles. +* link:http://witheve.com[Eve], an innovative language organized around reactive blocks of code. +* link:https://www.flapjax-lang.org/index.html[Flapjax] language. +* link:https://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.14.9769&rep=rep1&type=pdf[Designware: Software Development by Refinement], this paper presents ideas for building a system through composition. +* link:http://publications.csail.mit.edu/lcs/pubs/pdf/MIT-LCS-TM-061.pdf[Data flow programming] is not new. +* link:https://blog.janestreet.com/introducing-incremental/[Incremental]. +* link:https://en.wikipedia.org/wiki/Temporal_logic[Temporal Logic]. +* link:https://arxiv.org/abs/1104.2293[Reactive Imperative Programming with Dataflow Constraints]. In this paper the authors build a very similar bipartite data flow dependency graph. +* link:https://www.cs.cmu.edu/afs/cs/project/amulet/www/papers/toplas-constraint-experience.pdf[Garnet and Amulet] are toolkits for developing software using similar data flow techniques. +* link:https://www.amazon.com/Picturing-Quantum-Processes-Diagrammatic-Reasoning/dp/110710422X[Picturing Quantum Processes]. +* link:https://www.amazon.com/Invitation-Applied-Category-Theory-Compositionality/dp/1108711820[An Invitation to Applied Category Theory]. diff --git a/doc-site/content/en/ignore/search.md b/doc-site/content/en/ignore/search.md new file mode 100644 index 0000000..e3690fd --- /dev/null +++ b/doc-site/content/en/ignore/search.md @@ -0,0 +1,6 @@ +--- +title: Search Results +layout: search + +--- + diff --git a/doc-site/content/en/questions.md b/doc-site/content/en/questions.md new file mode 100644 index 0000000..9be7a41 --- /dev/null +++ b/doc-site/content/en/questions.md @@ -0,0 +1,35 @@ +--- +title: "Questions and Feedback" +weight: 70 +--- + +While we have given the current feature set a lot of consideration, we cannot understand all your constraints. +Let us know what you are thinking. +Your questions and feedback help us. + +### Ideas +* You want to more about how something works? +* You want to know why something works the way it does? +* How to integrate with your favorite library? +* What is a good pattern for expressing your particular problem? +* Do you have an interesting use case? +* Have you hit a barrier that makes it impossible to use? + +## Channels + +At the moment we would like to avoid creating yet one more community you need to sign up for. +Use these existing channels instead. + +### GitHub + +For Javascript/Typescript related questions ask on our Github Page: + +[bgjs Github](https://github.com/yahoo/bgjs/issues) + +For questions or feedback related to this documentation we have a separate Github Repository: + +[bgdocs Github](https://github.com/yahoo/bgdocs/issues) + +### Stack Overflow + +We will monitor StackOverflow for [Behavior Graph related questions](https://stackoverflow.com/questions/tagged/behavior-graph) if you tag them with `behavior-graph`. diff --git a/doc-site/content/en/quickstart.md b/doc-site/content/en/quickstart.md new file mode 100644 index 0000000..b6d0fae --- /dev/null +++ b/doc-site/content/en/quickstart.md @@ -0,0 +1,92 @@ +--- +title: "Quick Start" +weight: 10 +--- + +Using Behavior Graph is as simple as downloading it via your preferred format and importing it into your source. + +## Downloading + +### NPM + +Behavior Graph is hosted on NPM @ [behavior-graph](https://www.npmjs.com/package/behavior-graph). + +You may add it as a dependency in your project's __package.json__ manually or install it via the shell +It supports both CommonJS and module imports. + +```sh +npm install behavior-graph +``` + +Please search the web for any help using `npm`. + +### GitHub +Behavior Graph is available in source form via Github @ [yahoo/bgjs](https://www.github.com/yahoo/bgjs). + +### Javascript CDNs + +Behavior Graph is also available via a number of popular CDN Services. +You may prefer to use these when importing directly into the browser. + +* [Skypack.dev](https://www.skypack.dev/view/behavior-graph) +* [JSDelivr](https://www.jsdelivr.com/package/npm/behavior-graph) + + +## Importing + +Javascript imports require some knowledge of your environment which is beyond the scope of this guide. + +For modern environments: + +Node: `import * as bg from behavior-graph` + +or + +Browser: `import * as bg from "https://cdn.skypack.dev/behavior-graph";` + +Behavior Graph is also available as an IIFE which you can include as a script tag directly into the browser. + +`` + +The default export name is `bg` when using this method. + +## Quicker Start + +To start exploring feel free to use any of the following which have been preconfigured to use Behavior Graph. + +* [JSFiddle](https://jsfiddle.net/slevin11/akevq4hm/) +* [CodePen](https://codepen.io/slevin11/pen/XWzbMWZ) + +## Coding + +### Typescript or Javascript + +Behavior-Graph is written in Typescript. +It is usable directly from Javascript or Typescript code. +Type declaration files are provided for all APIs. + +### Hello, World! + +Once you've set up your environment, type in the following to see the magic inside the Javascript console. + +```javascript +let g = new bg.Graph(); +let e = new bg.Extent(g); +let m1 = e.moment(); +e.behavior() + .demands(m1) + .runs(() => { + console.log('Hello, World!') + }); +e.addToGraphWithAction(); +m1.updateWithAction(); +``` + +If this does not work, double check your imports and your environment. + +## Tutorials + +It is unlikely you will get very far with Behavior Graph without working through a [tutorial]({{< ref "tutorials/tutorial-1" >}}). +Please spend some time with them to practice writing Behavior Graph code. +They don't take very long, and you will be mentally stimulated and spiritually rewarded for your time. + diff --git a/doc-site/content/en/relatedwork.md b/doc-site/content/en/relatedwork.md new file mode 100644 index 0000000..a042022 --- /dev/null +++ b/doc-site/content/en/relatedwork.md @@ -0,0 +1,33 @@ +--- +title: "Related Work" +weight: 60 +--- + +We acknowledge the hard work and incredible contributions from everyone below. + +* [Cybernetics](https://en.wikipedia.org/wiki/Cybernetics) describes the "closed signaling loop", the essence of Unidirectional Data Flow architectures (aka MVI or Model View Intent). +* [Redux](https://redux.js.org) (and Flux) are popular Javascript state management frameworks organized around Unidirectional Data Flow. There are similar implementations for different platforms +* [re-frame/Clojure](https://github.com/day8/re-frame). Unidirectional Data Flow for Clojurescript +* [Functional Reactive Programming](https://en.wikipedia.org/wiki/Functional_reactive_programming) (FRP) is not new. +* [ReactiveX](http://reactivex.io) is a popular reactive programming implementation for many different imperative languages. +* [Mobius](https://github.com/spotify/mobius) is another take on Unidirectional Data Flow for the Android platform. +* [Observers](https://en.wikipedia.org/wiki/Observer_pattern) aren't new. +* [Cycle.js](https://cycle.js.org) Javascript reactive library. +* [MobX](https://mobx.js.org/README.html) Javascript reactive library. +* [REScala](https://www.rescala-lang.com) Scala reactive library +* [Apple's Combine](https://developer.apple.com/documentation/combine). +* [Java Flow](https://docs.oracle.com/javase/9/docs/api/java/util/concurrent/Flow.html). +* [State Charts(pdf)](http://www.inf.ed.ac.uk/teaching/courses/seoc/2005_2006/resources/statecharts.pdf). +* [X State](https://xstate.js.org), state chart library. +* [Event Bus/Pub-Sub](https://en.wikipedia.org/wiki/Publish–subscribe_pattern) is a pattern for building reactive style architectures. +* [Elm](https://elm-lang.org), an elegant functional programming language for the web. +* [Eve](http://witheve.com), an innovative language with reactive blocks of code. +* [Flapjax](https://www.flapjax-lang.org/index.html) language. +* [Designware: Software Development by Refinement (pdf)](https://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.14.9769&rep=rep1&type=pdf), this paper presents ideas for building a system through composition. +* [Data flow programming (pdf)](http://publications.csail.mit.edu/lcs/pubs/pdf/MIT-LCS-TM-061.pdf) is not new. +* [Incremental](https://blog.janestreet.com/introducing-incremental/). +* [Temporal Logic](https://en.wikipedia.org/wiki/Temporal_logic). +* [Reactive Imperative Programming with Dataflow Constraints](https://arxiv.org/abs/1104.2293). In this paper the authors build a very similar bipartite data flow dependency graph. +* [Garnet and Amulet (pdf)](https://www.cs.cmu.edu/afs/cs/project/amulet/www/papers/toplas-constraint-experience.pdf) are toolkits for developing software using similar data flow techniques. +* [Picturing Quantum Processes](https://www.amazon.com/Picturing-Quantum-Processes-Diagrammatic-Reasoning/dp/110710422X). +* [An Invitation to Applied Category Theory](https://www.amazon.com/Invitation-Applied-Category-Theory-Compositionality/dp/1108711820). diff --git a/doc-site/content/en/tutorials/_index.md b/doc-site/content/en/tutorials/_index.md new file mode 100644 index 0000000..af0b432 --- /dev/null +++ b/doc-site/content/en/tutorials/_index.md @@ -0,0 +1,4 @@ +--- +title: "Tutorials" +weight: 50 +--- diff --git a/doc-site/content/en/tutorials/tutorial-1.md b/doc-site/content/en/tutorials/tutorial-1.md new file mode 100644 index 0000000..d250a9c --- /dev/null +++ b/doc-site/content/en/tutorials/tutorial-1.md @@ -0,0 +1,589 @@ +--- +title: "Tutorial 1 - Basics" +--- + +Here we will introduce the essentials to get you started quickly using Behavior Graph. + +The recommended way to get started is to use our [preconfigured tutorial site](https://jsfiddle.net/slevin11/k2g6fov0/). + +If you prefer to set up your own environment please see the [Quick Start page]({{< ref quickstart >}}). +Make sure to open up the Javascript console. +That is where we will generate our output. + +## Hello, World! + +Type in the following into the editor. +You will gain more by typing it, as it forces you to think about each line. + + +{{< highlight javascript >}} +import * as bg from "https://cdn.skypack.dev/behavior-graph"; + +let g = new bg.Graph(); + +class HelloExtent extends bg.Extent { + constructor(graph) { + super(graph); + + this.person = this.state("Nobody"); + this.behavior() + .demands(this.person) + .runs(() => { + console.log("Hello, " + this.person.value + "!"); + }); + } +} + +let e = new HelloExtent(g); + +e.addToGraphWithAction(); + +g.action(() => { + e.person.update("World"); +}); +{{< / highlight >}} + +Run the code. +In the console you should see + +``` +"Hello, World!" +``` + + +### The Parts + +Let's review this in pieces. + +{{< highlight javascript >}} +import * as bg from "https://cdn.skypack.dev/behavior-graph"; +{{< / highlight >}} + +This is a standard Javascript import. +You may need to adjust it depending on your Javascript environment which is beyond the scope of this tutorial. +Behavior Graph is distributed though [NPM](https://www.npmjs.com/package/behavior-graph) and is available through a number of downstream CDNs. +See the [Quick Start page]({{< ref quickstart >}}) for more information. +Note that Behavior Graph is imported as `bg` here. +We will reference that in a few places in the tutorial. +Your import name may be different. + + +{{< highlight javascript >}} +let g = new bg.Graph(); +{{< / highlight >}} + +You must create an instance of a `Graph`. +You may have more than one instance, but all Behavior Graph elements are associated with a specific instance. + +{{< highlight javascript >}} +class HelloExtent extends bg.Extent { + constructor(graph) { + super(graph); +{{< / highlight >}} + +You will modularize your Behavior Graph code into __Extents__. +You do this by extending the built in `Extent` class and passing it your `Graph` instance in the constructor. +Extents collect Behaviors and Resources together with the same lifetime. + +{{< highlight javascript >}} + this.person = this.state("Nobody"); +{{< / highlight >}} + +`person` is a __Resource__. +Resources are containers for information. +This specifically is a __State__ resource. +State resources contain persistent information, i.e. it may be used in the future. +You will define state resources as properties on your Extent subclass and create them with the `.state()` factory method. +State resources always have an initial value. +Our `person` resource has an initial value of `"Nobody"`. + +{{< highlight javascript >}} + this.behavior() + .demands(this.person) + .runs(() => { + console.log("Hello, " + this.person.value + "!"); + }); +{{< / highlight >}} + +This is a __Behavior__. +Behaviors are units of functionality. +We create them with the `.behavior()` factory method that uses a fluent [`BehaviorBuilder`]({{< ref "api#behaviorbuildert" >}}) API. + +This behavior has two parts. +The `.demands()` clause states that this behavior depends on the resource `person`. + +The `.runs()` clause is the code that gets run whenever one (or more) of the demands is updated (has new information). +This one prints our greeting using `this.person.value`. +The `.value` property returns the contents of our `person` state resource. +A behavior must demand a resource in order to access its `.value` property. +(It can also access it if it supplies the resource as well.) + +{{< highlight javascript >}} +let e = new HelloExtent(g); +e.addToGraphWithAction(); +{{< / highlight >}} + +We will need to create an instance of our `HelloExtent` in order to add it to the graph. +Then we call `.addToGraphWithAction()` which adds the `HelloExtent`'s resource and behavior to our graph. +They will not perform any work until their extent has been added. + +{{< highlight javascript >}} +g.action(() => { + e.person.update("World"); +}); +{{< / highlight >}} + +Here we create a new Action using `.action()` on our Graph instance. +Action blocks are how we introduce new information from the outside. +In this case, we are providing the person's name by calling `.update()` on our `person` state resource. + +### How it works + +This call to `.action()` will start a series of steps. + +1. It will run the anonymous function given as a parameter. +2. `e.person.update()` will tell the graph to mark any demanding behaviors as activated. +In this case there is the only one demanding behavior. +3. The anonymous function will complete. +4. The graph will call the runs block on the one activated behavior. +5. That runs block prints out "Hello, World!" by accessing the `.value` of `person` which is the value we passed into the `.update()` method. +6. The `.action()` method completes and the program continues. + +All of these steps together make up a single Behavior Graph __Event__. + +## Doing More + +While this may seem like a tedious implementation of "Hello, World", we have already established a foundation that will let this program grow to arbitrary complexity. +The computer can use these components to support us throughout the development process. + +Let's introduce a second reason why we may need to print our greeting. + +_The highlighted lines will always be the new or updated lines_ + +{{< highlight javascript "hl_lines=2 4 6" >}} + this.person = this.state("Nobody"); + this.greeting = this.state("Greetings"); + this.behavior() + .demands(this.person, this.greeting) + .runs(() => { + console.log(this.greeting.value + ", " + this.person.value + "!"); + }); +{{< / highlight >}} + +First we create a second state resource, `greeting`. +Then we add `greeting` as an additional demand. +We must add it as a demand because we access its `.value` property. +Behavior Graph will raise an error if we do not. +This explicitness is by design. +Finally we modify our message to use `greeting.value`. + +When we run our program now it should produce + +``` +"Greetings, World!" +``` + +If we want to get back to our original message we can add more to our action. + +{{< highlight javascript "hl_lines=3">}} +g.action(() => { + e.person.update("World"); + e.greeting.update("Hello"); +}); +{{< / highlight >}} + +Now we have + +``` +"Hello, World!" +``` + +### Multiple Updates + +This illustrates an important distinction between Behavior Graph and many reactive libraries. +Our behavior demands multiple resources. +That means whenever either `person` or `greeting` __or both__ update our behavior should run. +However it doesn't run immediately, it is only __activated__. + +Inside our action we update both `person` and `greeting`. +Our behavior that demands them will not run until the entire action block has completed. +All updates inside a single action are treated as if they happened at the same time. +This means our behavior runs only once. + +We aren't required to provide both just because we demand both. +State resources persist their value from action to action. +Let's add an additional action to see this. + +{{< highlight javascript "hl_lines=5-7">}} +g.action(() => { + e.person.update("World"); + e.greeting.update("Hello"); +}); +g.action(() => { + e.greeting.update("Goodbye"); +}); +{{< / highlight >}} + +Now in our console it should print + +``` +"Hello, World!" +"Goodbye, World!" +``` + +"World" persisted into the second event. While "Goodbye" replaced the previous greeting. + +## Moments + +Not all information persists. +Sometimes things just happen. +A button press is a typical example. +We can model this information with __Moment__ resources. + +{{< highlight javascript "hl_lines=3 5 7-9">}} + this.person = this.state("Nobody"); + this.greeting = this.state("Greetings"); + this.button = this.moment(); + this.behavior() + .demands(this.person, this.greeting, this.button) + .runs(() => { + if (this.button.justUpdated) { + console.log(this.greeting.value + ", " + this.person.value + "!"); + } + }); +{{< / highlight >}} + +First we create a `button` resource. +We create it with a `.moment()` factory method on our Extent subclass. +Then we add it to our behavior's list of demands so it runs when `button` updates. + +Inside our runs block, we've gated our log statement by checking against `button.justUpdated`. +This will be true only if some other part of our code called `button.update()` during the same event. + +### Press the Button + +If you run the program now you will get no output. +This is because we only update the `person` and `greeting` resources and our `log` statement only runs when `button.justUpdated` is true. + +So lets add some additional lines to simulate a button press. + +{{< highlight javascript "hl_lines=8-10">}} +g.action(() => { + e.person.update("World"); + e.greeting.update("Hello"); +}); +g.action(() => { + e.greeting.update("Goodbye"); +}); +g.action(() => { + e.button.update(); +}); +{{< / highlight >}} + +Now our program outputs: + +``` +"Goodbye, World!" +``` + +The first two actions only update the state resources. +Our behavior is run but the `if (this.button.justUpdated)` check prevents anything from happening. +The third action causes the behavior to run as well. +This time the `if` check passes and it logs the message based on prior updates. + +Of course they don't need to be in separate actions. + +{{< highlight javascript "hl_lines=3">}} +g.action(() => { + e.button.update(); + e.greeting.update("Nevermind"); +}); +{{< / highlight >}} + +Will output: + +``` +"Nevermind, World!" +``` + +The message changed because both `button` updated as well as `greeting` in that same action. +The order in which they were updated inside the action is irrelevant to any demanding behaviors. + +## A Graph + +With only one behavior, it is difficult to call it a behavior graph. +The real power of Behavior Graph comes with the ability to incrementally introduce related functionality. +Behaviors will often depend on information provided by other behaviors. + +### Supplies + +Imagine, for security sake, that we would like to introduce logging into our "Hello, World" program. + +{{< highlight javascript "hl_lines=2 4 7 9">}} + this.button = this.moment(); + this.message = this.state(null); + this.behavior() + .supplies(this.message) + .demands(this.person, this.greeting, this.button) + .runs(() => { + this.message.update(this.greeting.value + ", " + this.person.value + "!"); + if (this.button.justUpdated) { + console.log(this.message.value); + } + }); +{{< / highlight >}} + +We add a new state resource, `message`, to save the current message. +We add this resource to a new supplies clause of our behavior definition with `.supplies()`. +__Supplies__ are resources that this behavior is solely responsible for. +It means that a behavior can both read a resource's `.value` and `.update()` it as well. + +We call `message.update()` with the text contents of the greeting to save them for later. + +{{< alert title="Rule" color="primary" >}} +A resource can only be supplied by one behavior. +A behavior can supply multiple resources. +It is an error to call `.update()` on a resource inside a behavior if it does not appear in the supplies clause. + +Actions can call `.update()` on a resource without specifying that they do so. +Actions cannot `.update()` a resource if it is supplied by a behavior. +{{< /alert >}} + +### Logging Behavior + +We can introduce the logging functionality by adding an additional behavior. + +{{< highlight javascript "hl_lines=6-10">}} + if (this.button.justUpdated) { + console.log(this.message.value); + } + }); + + this.behavior() + .demands(this.message) + .runs(() => { + console.log("Message changed to: " + this.message.value); + }); +{{< / highlight >}} + +This new behavior demands `message`. +This means it will run whenever `message` updates. +Our output shows this result: + +``` +"Message changed to: Hello, World!" +"Message changed to: Goodbye, World!" +"Nevermind, World!" +"Message changed to: Nevermind, World!" +``` + +As you can see our new logging behavior runs and generates output each time the message changes. + +## Events + +In Behavior Graph we call a single pass through the graph (from the start of an action to the last output) an [__Event__]({{< ref "api#graphevent" >}}). +Our current output is the result of three events. + +__First Event:__ +```mermaid +graph LR + a["Action:
person=>World
greeting=>Hello"] --> b["Behavior 1:
message=>Hello, World!"] --> c["Behavior 2:
message change logged"] +``` + +__Second Event:__ +```mermaid +graph LR + a["Action:
greeting=>Goodbye"] --> b["Behavior 1:
message=>Goodbye, World!"] --> c["Behavior 2:
message change logged"] +``` + +__Third Event:__ +```mermaid +graph LR + a["Action:
button updates
greeting=>Nevermind"] --> b["Behavior 1:
message=>Nevermind, World!
message printed"] --> c["Behavior 2:
message change logged"] +``` + +### The Same Event + +Every time a resource is updated, it is assigned the current event. +So in the __First Event__ example above, when `person` and `greeting` update, they get pointers to that same event in their `.event` property. +Then when `message` updates in the first behavior it also gets a pointer to this same event. + +We can access this event inside any behavior that we demand (or supply). +This can use this to append a timestamp to our log messages. + +{{< highlight javascript "hl_lines=4">}} + this.behavior() + .demands(this.message) + .runs(() => { + console.log("Message changed to: " + this.message.value + " : " + this.message.event.timestamp); + }); +{{< / highlight >}} + +You should now see something similar to the lines below + +``` +"Message changed to: Hello, World! : Fri Jan 28 2022 16:43:43 GMT-0800" +"Message changed to: Goodbye, World! : Fri Jan 28 2022 16:43:43 GMT-0800" +"Nevermind, World!" +"Message changed to: Nevermind, World! : Fri Jan 28 2022 16:43:43 GMT-0800" +``` + +### What Just Happened? + +Using `.justUpdated` is a powerful tool for organizing our code into related functionality. +We will add additional logging to see how this works. +First we will track when we send the message. + +{{< highlight javascript "hl_lines=2 4 10 15 17-22">}} + this.message = this.state(null); + this.sentMessage = this.moment(); + this.behavior() + .supplies(this.message, this.sentMessage) + .demands(this.person, this.greeting, this.button) + .runs(() => { + this.message.update(this.greeting.value + ", " + this.person.value + "!"); + if (this.button.justUpdated) { + console.log(this.message.value); + this.sentMessage.update(); + } + }); +{{< / highlight >}} + +We create a moment resource for `sentMessage`. +Sending the message is a one off action, so we keep track of that with a moment. +We will be calling `.update()` on `sentMessage` so we need to add it to the list of supplies. +We call `this.sentMessage.update()` right after the `console.log` call to track when we actually print out our message. + +Note that a behavior can supply more than one resource. +This is a common pattern that lets us group related logic together without having to jump through hoops to avoid duplication. + +Next we modify our logging message to demand this additional resource. + +{{< highlight javascript "hl_lines=2 4 6-9">}} + this.behavior() + .demands(this.message, this.sentMessage) + .runs(() => { + if (this.message.justUpdated) { + console.log("Message changed to: " + this.message.value + " : " + this.message.event.timestamp); + } + if (this.sentMessage.justUpdated) { + console.log("Message sent: " + this.message.value + " : " + this.message.event.timestamp); + } + }); +{{< / highlight >}} + +This behavior now demands `sentMessage` which means it will run whenever that resource is updated. +Inside our run block we check to see which resource was updated and generate the correct log message. +It may be the case that either one or both is updated. + +You will find yourself using this "what just happened?" pattern in many of your behaviors. + +Running your program should looks like this: + +``` +"Message changed to: Hello, World! : Sat Jan 29 2022 08:33:05 GMT-0800" +"Message changed to: Goodbye, World! : Sat Jan 29 2022 08:33:05 GMT-0800" +"Nevermind, World!" +"Message changed to: Nevermind, World! : Sat Jan 29 2022 08:33:05 GMT-0800" +"Message sent: Nevermind, World! : Sat Jan 29 2022 08:33:05 GMT-0800" +``` + +## Challenge + +Can you introduce a single resource that turns on or off our newly added logging? +Try to do this challenge before looking at the answer. + +Here's some hints: +* Try adding a state resource. +* You'll need to demand it in a behavior and introduce some additional logic. + +### Answer + +{{< highlight javascript "hl_lines=2 15 17 24">}} + this.sentMessage = this.moment(); + this.loggingEnabled = this.state(true); + this.behavior() + .supplies(this.message, this.sentMessage) + .demands(this.person, this.greeting, this.button) + .runs(() => { + this.message.update(this.greeting.value + ", " + this.person.value + "!"); + if (this.button.justUpdated) { + console.log(this.message.value); + this.sentMessage.update(); + } + }); + + this.behavior() + .demands(this.message, this.sentMessage, this.loggingEnabled) + .runs(() => { + if (this.loggingEnabled.value) { + if (this.message.justUpdated) { + console.log("Message changed to: " + this.message.value + " : " + this.message.event.timestamp); + } + if (this.sentMessage.justUpdated) { + console.log("Message sent: " + this.message.value + " : " + this.message.event.timestamp); + } + } + }); +{{< / highlight >}} + +`loggingEnabled` is our new resource. +We want it to persist so we use a state resource. +It defaults to `true` meaning logging is on. + +We then need to demand it inside our logging behavior in order to access its `.value` property. +If we try to access `.value` without demanding it, Behavior Graph will raise an error. + +We can modify our last action to see it work. + +{{< highlight javascript "hl_lines=4">}} +g.action(() => { + e.button.update(); + e.greeting.update("Nevermind"); + e.loggingEnabled.update(false); +}); +{{< / highlight >}} + +After adding this additional line, running our code looks like this. + +``` +"Message changed to: Hello, World! : Sat Jan 29 2022 08:39:43 GMT-0800" +"Message changed to: Goodbye, World! : Sat Jan 29 2022 08:39:43 GMT-0800" +"Nevermind, World!" +``` + +We no longer log the last two messages because logging was turned off in the same action. +Notice how even though `loggingEnabled.update(false)` comes after our updates, we still disable logging for the same event. +If you were to do this without Behavior Graph, using status quo method calls and property updates, you would need to ensure that `loggingEnabled` changes to `false` _before_ the other updates. +It would be a different result if you updated it _after_. +_The ability to remove the hidden complexity that comes with sequencing is a programming superpower._ +Behavior Graph gives you this feature for free. + +### Ordering Resources + +You may notice that although `.loggingEnabled` is a demand, we don't actually need it to to be a reason for our logging behavior to run. +We only need to check its `.value`. +Behavior Graph lets us lighten this constraint. + +{{< highlight javascript "hl_lines=2">}} + this.behavior() + .demands(this.message, this.sentMessage, this.loggingEnabled.order) + .runs(() => { + if (this.loggingEnabled.value) { + if (this.message.justUpdated) { +{{< / highlight >}} + +We can add `.order` to any resource inside our demands clause. +When we do this, updating that resource will not activate this behavior. +This can give us some additional accuracy when specifying how our behaviors are linked. + +## Complete + +Congratulations! You have completed this first tutorial. +You can see the [finished tutorial code here](https://jsfiddle.net/slevin11/uej3y09f/). + +While you may feel that there were many new concepts introduced, we have already covered the majority of them. +You will find they come naturally with some practice. +The remaining tutorials give you a taste for how Behavior Graph works inside real interactive programs. + + diff --git a/doc-site/content/en/tutorials/tutorial-2.md b/doc-site/content/en/tutorials/tutorial-2.md new file mode 100644 index 0000000..8a494bf --- /dev/null +++ b/doc-site/content/en/tutorials/tutorial-2.md @@ -0,0 +1,446 @@ +--- +title: "Tutorial 2 - IO" +--- + +This tutorial will show how Behavior Graph interacts with real inputs and outputs to produce a working application. +In this case we will build the control system for a thermostat, the device in your house that controls the heat. + +![Thermostat]({{< static "images/thermostat-ui.png" >}}) + +This simplified thermostat has two buttons, __Up__ and __Down__ for raising and lowering the desired temperature. +It also periodically gets external updates of the current temperature. +If the desired temperature is above the current temperature, we will turn on the heat. +And once they are the same, the heat will turn off. + +## Initial Code + +We have created a starter project using [JSFiddle](https://jsfiddle.net/slevin11/k3z2uysx/). +You should use that for this tutorial. +It has some simple HTML/CSS to represent the Thermostat's user interface. +If you wish to use your own environment you will need to copy the HTML and CSS from this JSFiddle site into your own. + +The initial setup code has been provided for you. + +{{< highlight javascript "hl_lines=">}} +import * as bg from "https://cdn.skypack.dev/behavior-graph"; + +class Thermostat extends bg.Extent { + constructor(graph) { + super(graph); + } +} + +let graph = new bg.Graph(); +let tm = new Thermostat(graph); +tm.addToGraphWithAction(); +{{< / highlight >}} + +The bulk of our application will exist inside our `Thermostat` subclass of `Extent`. + +## Desired Temperature + +The first part of our logic will focus on setting the desired temperature. +The related elements look something like this. + +![Desired Temperature]({{< static "images/thermostat-temp.svg" >}}) + +First we need a state resource to track our desired temperature and a behavior to supply it. + +{{< highlight javascript "hl_lines=5-10">}} +class Thermostat extends bg.Extent { + constructor(graph) { + super(graph); + + this.desiredTemperature = this.state(60); + this.behavior() + .supplies(this.desiredTemperature) + .runs(() => { + // desired temperature logic will go here + }); + } +} +{{< / highlight >}} + +`desiredTemperature` is a state resource with an initial value of 60. +We want a state resource because it is information we intend to use in the future. +Our new behavior supplies this resource because we plan on calling `desiredTemperature.update()` inside the runs block. + +### Button Presses + +Our thermostat will need to respond to the button press events that come from our HTML buttons. + +{{< highlight javascript "hl_lines=3-6">}} + super(graph); + + this.up = this.moment(); + document.querySelector('#up').addEventListener('click', () => { + this.up.updateWithAction(); + }); + + this.desiredTemperature = this.state(60); +{{< / highlight >}} + +We create an `up` moment resource to track when the Up button is pressed. +Then we use standard DOM manipulation code to respond to the HTML click event. +We call `this.up.updateWithAction()` to track this event in our moment resource. + +`.updateWithAction()` is syntactic sugar for creating a new action and calling `.update()`. +It is the same as if we typed this instead: + +{{< highlight javascript "hl_lines=">}} + document.querySelector('#up').addEventListener('click', () => { + this.graph.action(() => { + this.up.update(); + }); + }); +{{< / highlight >}} + +### Responding to the Button + +We need to modify our behavior to respond to this update. + +{{< highlight javascript "hl_lines=4 6-8">}} + this.desiredTemperature = this.state(60); + this.behavior() + .supplies(this.desiredTemperature) + .demands(this.up) + .runs(() => { + if (this.up.justUpdated) { + this.desiredTemperature.update(this.desiredTemperature.value + 1); + } + }); +{{< / highlight >}} + + +We add `up` to our list of demands. +This ensures that this behavior activates whenever `up` is updated. +Inside the run block we check for `.justUpdated`. +If so, we update the `desiredTemperature` by incrementing it from its previous `.value`. + +{{< alert title="Access Rules" color="primary" >}} +1. You can only access `.justUpdated` inside behaviors that demand (or supply) that resource. +Otherwise Behavior Graph will raise an error. +2. You can only access `.value` inside behaviors that demand (or supply) that resource. +Otherwise Behavior Graph will raise an error. +3. You can only call `.update()` inside a behavior that supplies that resource. +A resource can only be supplied by one behavior. +Behavior Graph will raise an error if you do this incorrectly. +{{< /alert >}} + +These rules are essential to allowing Behavior Graph to ensure your resources are always in a consistent state. + +### Output + +At this point our `desiredTemperature` changes when you press the Up button. +But we don't update the display. +We add that here. + +{{< highlight javascript "hl_lines=8-10">}} + this.behavior() + .supplies(this.desiredTemperature) + .demands(this.up) + .runs(() => { + if (this.up.justUpdated) { + this.desiredTemperature.update(this.desiredTemperature.value + 1); + } + this.sideEffect(() => { + document.querySelector('#desiredTemperature').innerText = this.desiredTemperature.value; + }); + }); +{{< / highlight >}} + +This behavior creates a __Side Effect__ block. +Inside that block we use standard DOM methods to update the temperature. +Now if you run this and click on the Up button you will see the temperature field appear and increment. + +Side effects are the correct way to generate output from inside a behavior. +Although a side effect is created inside a behavior, it will only run after all other behaviors have completed running. +This ensures that all our internal state has settled before calling code that may potentially access it. + +Side effects do not have a restriction on what resources they can access, unlike the behavior in which they are defined. + +### Down + +We can add the handling for our Down button in a similar way. + +{{< highlight javascript "hl_lines=6-9">}} + this.up = this.moment(); + document.querySelector('#up').addEventListener('click', () => { + this.up.updateWithAction(); + }); + + this.down = this.moment(); + document.querySelector('#down').addEventListener('click', () => { + this.down.updateWithAction(); + }); +{{< / highlight >}} + +And modify our behavior to respond. + +{{< highlight javascript "hl_lines=3 7-9">}} + this.behavior() + .supplies(this.desiredTemperature) + .demands(this.up, this.down) + .runs(() => { + if (this.up.justUpdated) { + this.desiredTemperature.update(this.desiredTemperature.value + 1); + } else if (this.down.justUpdated) { + this.desiredTemperature.update(this.desiredTemperature.value - 1); + } + this.sideEffect(() => { +{{< / highlight >}} + +Run the program. +Clicking on the Up and Down buttons should now move the desired temperature display up and down. + +### AddedToGraph + +You may have noticed that the desired temperature display doesn't show up until after we've tapped on one of the buttons. +This is because our behavior only runs when one of its demands is updated. +What we would like to do is also run it once at the beginning. + +{{< highlight javascript "hl_lines=3">}} + this.behavior() + .supplies(this.desiredTemperature) + .demands(this.up, this.down, this.addedToGraph) + .runs(() => { + if (this.up.justUpdated) { +{{< / highlight >}} + +We add the `this.addedToGraph` resource to our list of demands. +Now when you run the code you will see that the temperature appears at the beginning. + +`addedToGraph` is a built in state resource that is part of every Extent. +It is updated to `true` when the Extent is added to the graph. +Just like other resources you can demand it to get a behavior to run at the beginning. +And you can check it's `.justUpdated` property to specialize your logic when necessary. + +## Heat + +Now we need to introduce a separate bit of functionality to control the heating equipment. +This logic compares the current temperature to the desired temperature and turns on or off the heating equipment accordingly. + +![Current Temperature]({{< static "images/thermostat-heat.svg" >}}) + +### Current Temperature + +First we need a resource to track the current temperature, + +{{< highlight javascript "hl_lines=2">}} + this.desiredTemperature = this.state(60); + this.currentTemperature = this.state(60); +{{< / highlight >}} + +and a new behavior to update the UI when that resource updates. + +{{< highlight javascript "hl_lines=6-12">}} + this.sideEffect(() => { + document.querySelector('#desiredTemperature').innerText = this.desiredTemperature.value; + }); + }); + + this.behavior() + .demands(this.currentTemperature, this.addedToGraph) + .runs(() => { + this.sideEffect(() => { + document.querySelector('#currentTemperatureDisplay').innerText = this.currentTemperature.value; + }); + }); +{{< / highlight >}} + +Like with `desiredTemperature` this behavior runs whenever `currentTemperature` updates as well as once at the beginning. +It uses a side effect to update our UI. + +### Heat On + +Next we need a resource to track if the heat is on or not. + +{{< highlight javascript "hl_lines=3">}} + this.desiredTemperature = this.state(60); + this.currentTemperature = this.state(60); + this.heatOn = this.state(false); +{{< / highlight >}} + +By default the `heatOn` state resource is `false` indicating that it is off. + +{{< highlight javascript "hl_lines=7-13">}} + .runs(() => { + this.sideEffect(() => { + document.querySelector('#currentTemperatureDisplay').innerText = this.currentTemperature.value; + }); + }); + + this.behavior() + .supplies(this.heatOn) + .demands(this.currentTemperature, this.desiredTemperature) + .runs(() => { + let heatOn = this.desiredTemperature.value > this.currentTemperature.value; + this.heatOn.update(heatOn); + }); +{{< / highlight >}} + +Here we add another new behavior. +It is responsible for updating `heatOn` so we add it as a supply. +It uses both `currentTemperature` and `desiredTemperature` for its logic, so both are demands. +When it runs, it updates `heatOn` to true if our `currentTemperature` is too low. + +### Heat Display + +We want our display to update alongside the `heatOn`. +So we add that logic to our new behavior. + +{{< highlight javascript "hl_lines=3 7-9">}} + this.behavior() + .supplies(this.heatOn) + .demands(this.currentTemperature, this.desiredTemperature, this.addedToGraph) + .runs(() => { + let heatOn = this.desiredTemperature.value > this.currentTemperature.value; + this.heatOn.update(heatOn); + this.sideEffect(() => { + document.querySelector('#heatStatus').innerText = this.heatOn.value ? "On" : "Off" + }); + }); +{{< / highlight >}} + +We demand `addedToGraph` to ensure we update the display when the thermostat starts. +We also add a side effect block to update the UI. + +Now when you click the Up and Down buttons you should see the heating display change based on `desiredTemperature` changes. + +### Heating Equipment + +In a real thermostat, whenever `heatOn` changes, we would send a signal to real heating equipment somewhere else in the house. +Since we don't have that available, we will simulate our own heat and demonstrate how we can mix in other asynchronous elements. + +We'll add a new behavior. + +{{< highlight javascript "hl_lines=6-14">}} + this.sideEffect(() => { + document.querySelector('#heatStatus').innerText = this.heatOn.value ? "On" : "Off" + }); + }); + + this.behavior() + .demands(this.heatOn) + .runs(() => { + if (this.heatOn.justUpdatedTo(true)) { + // turn heat on + } else if (this.heatOn.justUpdatedTo(false)) { + // turn heat off + } + }); +{{< / highlight >}} + +This new behavior responds to `heatOn` updates. +It uses `.justUpdatedTo()` to differentiate changing to true or false. + +At this point we want to make an important point about the way state resources work. +Even though the behavior that supplies `heatOn` calls `.update()` every time it runs, it doesn't necessarily update the state resource. +Behavior Graph uses `===` to check if the new value is different from the starting value. +If they are the same, the state resource does not actually update. +Therefore, demanding behaviors are not activated. + +As an example, if `heatOn.value` is currently `false`, calling `heatOn.update(true)` will update the resource and activate demanding behaviors. However, if in the next event we also call `heatOn.update(true)`, Behavior Graph will check `true === true` and therefore will not actually update or activate demanding behaviors. + +#### Turning On + +We can use the built-in Javascript API `setInterval()` to simulate our heat changing over a period of time. +When on, this timer will increment our current temperature by 1 every 1.5 seconds. + +{{< highlight javascript "hl_lines=2-8">}} + if (this.heatOn.justUpdatedTo(true)) { + this.sideEffect(() => { + this.heatingIntervalId = setInterval(() => { + this.action(() => { + this.currentTemperature.update(this.currentTemperature.value + 1); + }); + }, 1500); + }); + } else if (this.heatOn.justUpdatedTo(false)) { +{{< / highlight >}} + + +This branch creates a side effect which starts the timer and saves that timer directly to a normal property `heatingIntervalId`. +We will use this to stop the timer later. +When the timer fires, we create an action to bring new information into Behavior Graph. +In this case, the new information is that `currentTemperature` has increased by 1. +Note we are accessing `currentTemperature.value` inside a side effect block which means we don't need to add it as a demand of the behavior. + +`heatingIntervalId` is a normal Javascript property. +You are always welcome to use normal properties and methods inside behaviors however you like. +You just won't get the additional support from Behavior Graph for those uses. +In this case, we don't need to respond to any changes with it so we just save it to a property. + + +#### Turning Off + +If you run this program now, the heat will start incrementing but it won't stop once the heat turns off. +We will add an additional side effect for this. + +{{< highlight javascript "hl_lines=2-5">}} + } else if (this.heatOn.justUpdatedTo(false)) { + this.sideEffect(() => { + clearInterval(this.heatingIntervalId); + this.heatingIntervalId = null; + }); + } +{{< / highlight >}} + +This side effect cancels our timer when the heat turns off. +`clearInterval()` is a built-in Javascript method to cancel the timer. +We set the property to null for cleanliness. + +Now run the code and turn the desired temperature up a few degrees from the current temperature and wait. +You will see the current temperature slowly increase until they equal and the heat will turn off. + +## Behavior Graph Programming + +This code is typical Behavior Graph programming style. +The path we went through to get here is typical of the Behavior Graph programming process. +The important step is learning how to organize code into behaviors. + +### Control Flow for Free + +Behaviors are never called directly, which can feel like a lack of control. +This is a fair intuition, but also incorrect. +Behavior Graph improves our ability to express the intent of our code. +We do not think in terms of "do this now". +Instead we think, "here are the reasons why this should run". + +Behavior Graph determines the behavior that should run next based on which behaviors have been activated and their dependencies. +A behavior that may influence another behavior will always run first. + +Looking a the behaviors in our Thermostat program and their linked resources we can figure out exactly how things will run. +Here's the sequence of steps when we click the Up button. + +1. Action: `up.update()`, activate Behavior 1 +2. Behavior 1: `desiredTemperature.update(61)`, activate Behavior 2, create Side Effect 1 +3. Behavior 2: `heatOn.update(true)`, activate Behavior 3, create Side Effect 2 +4. Behavior 3: create Side Effect 3 +5. Side Effect 1: `#desiredTemperature` HTML element changes to "61" +6. Side Effect 2: `#heatStatus` HTML element changes to "On" +7. Side Effect 3: Create simulated "heating" timer + +The status quo approach of organizing around method calls leaves us open to potential errors as dependencies change. +With Behavior Graph, if we introduce a new dependency for Behavior 1, the rest of the control flow adapts. +Everything will continue to run in the correct order. +This is Behavior Graph doing the work for you. + +### Incremental Adoption + +Behavior Graph is not the solution to all programming problems. +It is a tool for structuring the event driven logic portion of your software. +Feel free to use it as much or as little as you like. + +When introducing it incrementally to an exiting codebase, it is easiest to work back from the output. +1. Find a place were you update the UI, start an animation, or make a network call. +2. Wrap that up in a side effect inside a behavior. +3. Then figure out what new information should cause that behavior to run. +4. Turn that information into resources. +5. Either update those resources inside action blocks or write new behaviors to supply them. +6. Repeat. + +## Congratulations + +Congratulations! You have completed the second tutorial. +You can see the [finished tutorial code here](https://jsfiddle.net/slevin11/kfuwrmb8/). diff --git a/doc-site/content/en/tutorials/tutorial-3.md b/doc-site/content/en/tutorials/tutorial-3.md new file mode 100644 index 0000000..d5b0846 --- /dev/null +++ b/doc-site/content/en/tutorials/tutorial-3.md @@ -0,0 +1,736 @@ +--- +title: "Tutorial 3 - Extents" +--- + +In this tutorial we will create a simple todo list. + +![Todo List]({{< static "images/todolist.png" >}}) + +A todo list is interesting because it has user interface elements with independent lifetimes. +When we start, our list is empty. +The visible interface elements are the header for adding new items and a footer for the remaining items. +After we click Save, a new item will appear with a checkbox for completing it, and a button for deleting it. +The list as a whole has a longer lifetime than the individual items. + +We will implement this by adding and removing Extents from the graph as we add and remove items from our list. +This is a powerful and practical technique that gives Behavior Graph a unique expressiveness in the state management realm. + +## Initial Code + +We have created a starter project using [JSFiddle](https://jsfiddle.net/slevin11/kuw2h1no/). +You should use that for this tutorial. +It has some simple HTML/CSS to represent the Todo List's user interface. +If you wish to use your own environment you will need to copy the HTML and CSS from this JSFiddle site into your own. + +We first want to set up the initial structure. + +{{< highlight javascript "hl_lines=">}} +import * as bg from "https://cdn.skypack.dev/behavior-graph"; + +class ListExtent extends bg.Extent { + constructor(graph) { + super(graph); + + } +} + +let graph = new bg.Graph(); +let list = new ListExtent(graph); +list.addToGraphWithAction(); +{{< / highlight >}} + +## Adding Items + +_New code for you to add or modify will always be highlighted._ + +In order to add a new item, + +{{< highlight javascript "hl_lines=5-16">}} +class ListExtent extends bg.Extent { + constructor(graph) { + super(graph); + + this.save = this.moment(); + document.querySelector('#save').addEventListener('click', () => { + this.save.updateWithAction(document.querySelector('#new-item-text').value); + }); + + this.behavior() + .demands(this.save) + .runs(() => { + // do adding here + }); +{{< / highlight >}} + +We create a `save` moment resource to model the interaction of clicking on the Save button after typing in a new todo. +We use a normal DOM event to call `save.updateWithAction()` when the button it pressed. + +Unlike in previous tutorials, with this moment resource we are passing our update method a parameter which contains the value of the text field. +Moments often carry information along with them, in this case we would like to know the textual content of the new item. + +Next we create an empty behavior, demanding the `save` resource. +When `save` is updated, we want this behavior to create a list item and update the UI. + +### What is an Item? + +A typical way to represent a list item is to create a data structure or object with the relevant data. +We can do something similar with a new Extent subclass. + +{{< highlight javascript "hl_lines=4-10">}} + } +} + +class ItemExtent extends bg.Extent { + constructor(graph, text, list) { + super(graph); + this.list = list; + this.itemText = this.state(text); + } +} + +let graph = new bg.Graph(); +let list = new ListExtent(graph); +list.addToGraphWithAction(); +{{< / highlight >}} + +We add a new `ItemExtent` subclass and pass in some information into its constructor. +1. A required `Graph` instance +2. The text of the new todo list item which we store in an `itemText` state resource +3. A pointer to the parent `ListExtent` instance which we will use later + +### Creating an ItemExtent + +Back in our `ListExtent`, inside our behavior we can create an `ItemExtent` and add it to the graph. + +{{< highlight javascript "hl_lines=5-7">}} + this.behavior() + .demands(this.save) + .runs(() => { + if (this.save.justUpdated) { + let item = new ItemExtent(this.graph, this.save.value, this); + this.addChildLifetime(item); + item.addToGraph(); + } + }); +{{< / highlight >}} + +We create the new item with the contents of the text field. +Then we call `.addChildLifetime(item)`. +This lets Behavior Graph know that our `ListExtent` instance will always be around longer than any individual `ItemExtent`. +This will make it easier to connect behaviors in our `ItemExtent` to resources in our `ListExtent`. +We will see more on that later. + +Next we call `item.addToGraph()`. +Adding an extent to the graph is a necessary step. +Until we do this, any behaviors or resources in that extent will not perform their expected roles. + +### Collecting the Items + +We also need a way to keep track of these items as they are added. + +{{< highlight javascript "hl_lines=1 4 11-12">}} + this.allItems = this.state([]); + + this.behavior() + .supplies(this.allItems) + .demands(this.save) + .runs(() => { + if (this.save.justUpdated) { + let item = new ItemExtent(this.graph, this.save.value, this); + this.addChildLifetime(item); + item.addToGraph(); + this.allItems.value.push(item); + this.allItems.updateForce(this.allItems.value); + } + }); +{{< / highlight >}} + +`allItems` is a state resource initialized with an empty array. +We supply it because we will be updating it inside this behavior. +Whenever we create a new item we will append that `ItemExtent` instance to the end of that array via its `.value` property and the built in `Array.push()` method. +It is typical when working with extents that come and go to store them in a state resource or a collection inside a state resource. + +Lastly, changing the contents of a collection is not equivalent to calling `.update()` on the owning resource. +We must update the resource so that demanding behaviors will be notified. +To do this we update the resource with its own contents. +We do this with `.updateForce()`. +We cannot just call `.update()` because the contents are still the same array instance. +`.update()` automatically filters out updates when the old value `===` the new value. +`.updateForce()` works identically but ignores this check. +This is a common pattern when storing collections inside a resource. + +### Updating the UI + +Adding an item still doesn't update the UI to match. +Inside our `ItemExtent` we add some code to create a DOM node. + +{{< highlight javascript "hl_lines=6">}} +class ItemExtent extends bg.Extent { + constructor(graph, text, list) { + super(graph); + this.list = list; + this.itemText = this.state(text); + this.itemElement = document.querySelector('#templates .list-item').cloneNode(true); + } +} +{{< / highlight >}} + +This is a normal property that points to a DOM element we create by cloning some template content inside the existing HTML document. +Then inside our `ListExtent` behavior we can add our list item UI. + +{{< highlight javascript "hl_lines=8-11">}} + .runs(() => { + if (this.save.justUpdated) { + let item = new ItemExtent(this.graph, this.save.value, this); + this.addChildLifetime(item); + item.addToGraph(); + this.allItems.value.push(item); + this.allItems.updateForce(this.allItems.value); + this.sideEffect(() => { + document.querySelector('#list').appendChild(item.itemElement); + document.querySelector('#new-item-text').value = ''; + }); + } +{{< / highlight >}} + +This side effect adds the DOM element that our new `ListExtent` instance points to. +It also clears the text field so we can add additional items. + +Try adding some items by typing in the box and clicking Save. +It seems to add items but we only see empty text. +We can fix that by using our `addedToGraph` built in resource. + +Inside `ItemExtent` a new behavior. + +{{< highlight javascript "hl_lines=4-10">}} + this.itemText = this.state(text); + this.itemElement = document.querySelector('#templates .list-item').cloneNode(true); + + this.behavior() + .demands(this.itemText, this.addedToGraph) + .runs(() => { + this.sideEffect(() => { + this.itemElement.querySelector('.item-text').innerText = this.itemText.value; + }); + }); +{{< / highlight >}} + +This behavior will run when the `ItemExtent` is added to the graph updating its `innerText` HTML content. +We also added a demand on `itemText` since we would expect that to change the UI if it ever changes as well. +Now running our code and adding a few items will show our list correctly. + +### Completing Items + +There's a checkbox to complete a todo list item. +Checking it at this point does nothing. +Let's fix that. + +Inside `ItemExtent` + +{{< highlight javascript "hl_lines=4-7">}} + this.list = list; + this.itemText = this.state(text); + this.itemElement = document.querySelector('#templates .list-item').cloneNode(true); + this.completed = this.state(false); + this.itemElement.querySelector('.completed-checkbox').addEventListener('change', () => { + this.completed.updateWithAction(!this.completed.value); + }); +{{< / highlight >}} + +We add a new `completed` state resource that defaults to false. +We also add a DOM event for when the checkbox is checked so we can update `completed`. + +And we add an additional behavior inside `ItemExtent` + +{{< highlight javascript "hl_lines=1-12">}} + this.behavior() + .demands(this.completed, this.addedToGraph) + .runs(() => { + this.sideEffect(() => { + let completedClass = 'completed'; + if (this.completed.value) { + this.itemElement.classList.add(completedClass); + } else { + this.itemElement.classList.remove(completedClass); + } + }); + }); +{{< / highlight >}} + +This behavior creates a side effect which adds a "completed" class to our HTML item. +This uses the existing CSS to strike-through a completed todo item. +We also include `addedToGraph` as an additional demand. +It is not strictly necessary at this point because all todo items start off as not completed. +However, it is good practice to use it in behaviors that generate side effects to reflect the current state. +If we were to introduce functionality later for saving and restoring todo lists, we may have items that start in a completed state. + +Running this and checking/unchecking todo list items should update the UI accordingly. + +## Dynamic Behaviors + +We will now introduce functionality that takes advantage of Behavior Graph's ability to dynamically adjust demands and supplies. + +### Remaining Items + +The "Remaining Items" footer of the UI does not update currently. +First we need it to respond when adding items. + +Inside `ListExtent` we add a new behavior. + +{{< highlight javascript "hl_lines=1-8">}} + this.behavior() + .demands(this.allItems, this.addedToGraph) + .runs(() => { + this.sideEffect(() => { + let count = this.allItems.value.filter(item => !item.completed.value).length; + document.querySelector('#remaining-count').textContent = count; + }); + }); +{{< / highlight >}} + +This behavior will create a side effect to update the remaining items text to match the current number of non-completed items in the list. +`allItems` is a demand because we want to run it whenever we add a new item to the list. +Inside the side effect we are able to iterate over the array of `ItemExtent` instances to check the `.value` of their `completed` state resource. +`addedToGraph` ensures we have the correct starting value in there since it starts out empty. + +Now try adding a few items to the list and you will see the remaining items count increment. + +### Updating Remaining Items + +If you try to complete an item however our remaining items count does not change. +This is because that new behavior does not demand the `completed` resource from our `ItemExtent` instances. +However, we cannot just add it inside the list of demands because the set of `ItemExtent` instances changes over time. + +Behaviors have another clause for handling these situations. + +{{< highlight javascript "hl_lines=3-5">}} + this.behavior() + .demands(this.allItems, this.added) + .dynamicDemands([this.allItems], () => { + return this.allItems.value.map(item => item.completed); + }) + .runs(() => { + this.sideEffect(() => { + let count = this.allItems.value.filter(item => !item.completed.value).length; + document.querySelector('#remaining-count').textContent = count; + }); + }); +{{< / highlight >}} + +`.dynamicDemands()` is another clause when creating a behavior that lets you specify an additional list of demands that can change. +It takes two parameters. +The first is an array of resources. +Whenever any of those update, it will run the anonymous function in the second parameter. +That function returns a list of additional demands this behavior should have. + +Here our dynamic demands clause will return an array containing the `completed` resource from each `ItemExtent` instance. +So each time we add a new item, our behavior will adapt so that it will run when the `completed` resource for that item updates. + +Now try running the code. +You will see that adding new items updates the remaining items count. +And you will see that checking and unchecking the box on those items affects the remaining count as well. + +### Remaining Items Revisited + +Its worth a little extra effort to consider what we just did. +The _entire_ remaining items feature is defined by this single behavior. + +Let's compare this with a status quo implementation: methods, properties, and objects. +First we might have a method similar to our run block to update the UI + +```javascript +// Hypothetical Code -- Don't type this in +updateRemainingCount() { + let count = this.allItems.filter(item => !item.completed).length; + document.querySelector('#remaining-count').textContent = count; +} +``` + +That seems reasonable, but its not enough. +We need to go inside another method somewhere else in this same class to ensure this gets called when we add a new item. +Perhaps it might look like this: + +```javascript +// Hypothetical Code -- Don't type this in +saveButtonPressed(text) { + let save = new Item(text); + this.allItems.push(save); + this.updateRemainingCount(); +} +``` + +Ok, so the feature is in two places. +That's manageable. +Unfortunately, to handle completing, we still need to call in from another place in the code inside the Item class. + +```javascript +// Hypothetical Code -- Don't type this in +completeChecked(checked) { + this.completed = checked; + this.updateRemainingCount(); +} +``` + +Now our feature is spread across multiple classes. +And when we add a way to remove items we will need to involve another code-path. +This type of spread out logic is a real challenge for developers. +It is incredibly easy to miss a case. + +Production software is significantly more complex than this trivial example. +Most developers are swimming in control flows like this. +Behavior Graph lets us collect the "what" and the "why" all together in the same behavior. +The problem literally disappears. + + +## Deleting Items + +We also have a Delete button on each list item which does nothing currently. +We will fix that now. + +Inside `ItemExtent` we add some button click handling. + +{{< highlight javascript "hl_lines=6-8">}} + this.itemElement = document.querySelector('#templates .list-item').cloneNode(true); + this.completed = this.state(false); + this.itemElement.querySelector('.completed-checkbox').addEventListener('change', () => { + this.completed.updateWithAction(!this.completed.value); + }); + this.itemElement.querySelector('.item-delete').addEventListener('click', () => { + this.list.removeItem.updateWithAction(this); + }); +{{< / highlight >}} + +This takes a DOM event and updates the `removeItem` resource on `ListExtent` (which we haven't added yet). +It is common to interact with resources on other extents and a source of conceptual power. +Here we are saying, "this list item is requesting to be removed." + +Note that each `ItemExtent`'s Delete button updates the same `list.removeItem` resource. +We are allowed to update resources from multiple actions because only one action will happen during a single event. + +Now, inside `ListExtent`, + +{{< highlight javascript "hl_lines=2 6 8 18-25">}} + this.allItems = this.state([]); + this.removeItem = this.moment(); + + this.behavior() + .supplies(this.allItems) + .demands(this.save, this.removeItem) + .runs(() => { + if (this.save.justUpdated) { + let item = new ItemExtent(this.graph, this.save.value, this); + this.addChildLifetime(item); + item.addToGraph(); + this.allItems.value.push(item); + this.allItems.updateForce(this.allItems.value); + this.sideEffect(() => { + document.querySelector('#list').appendChild(item.itemElement); + document.querySelector('#new-item-text').value = ''; + }); + } else if (this.removeItem.justUpdated) { + let item = this.removeItem.value; + item.removeFromGraph(); + this.allItems.update(this.allItems.value.filter(listItem => listItem !== item)); + this.sideEffect(() => { + document.querySelector('#list').removeChild(item.itemElement); + }); + } + }); +{{< / highlight >}} + +These changes make up the remove item feature. +First we have a new `removeItem` moment resource. +`removeItem` models the concept of "a request to be removed happened". +We add `removeItem` as an additional demand on our `allItems` behavior. +This causes the behavior to run when a user clicks on a Delete button. + +It is common to refer to behaviors by the resources they supply. +This is because a behavior uniquely supplies those resources. +In this case we call this the `allItems` behavior. + +We are modifying this behavior because removing an item affects the list in `allItems`. +We could not put this logic in another behavior because a resource can only be supplied by one behavior. +Updating a resource can only happen in the one behavior that supplies it. + +Inside the runs block we add new checks for `save.justUpdated` and `removeItem.justUpdated`. +It is a common pattern to iterate through `.justUpdated` checks of the various demands to determine what happened. +In this case we remove the item from the list by building a new list without the item to remove. +So we do not need to call `.forceUpdate()` like we did when adding the item. +Our side effect ensures that the UI updates as well. + +Also note that we call`.removeFromGraph()` on the removed `ItemExtent`. +Extents should always be removed from the graph if they are no longer needed otherwise their behaviors will continue to run. + +### Remaining Items Re-revisited + +You may also notice that the remaining items count now goes down if you remove an item that hasn't been completed yet. +We get this for free because we defined the remaining items on the `allItems` list. +If we were just using method calls to implement delete, we very likely would have removed the item from our list directly and then had to remember to call some `updateRemainingCount()` which could have easily been forgotten. + +This ability to make chances without introducing additional complexity is a hallmark of programming with Behavior Graph. +Once you've experienced it a few times you will find it difficult to give up. + +## Editing + +Now we will introduce some editing functionality. +This will cover some additional uses of dynamic behaviors. +We will allow the user to click on a particular todo list item to select it. +While selected, the user can edit the text inside the main text field. + +### Selecting + +The first step is to use a DOM event to identify when we have selected a particular item. + +Inside `ItemExtent` add another handler. + +{{< highlight javascript "hl_lines=4-6">}} + this.itemElement.querySelector('.item-delete').addEventListener('click', () => { + this.list.removeItem.updateWithAction(this); + }); + this.itemElement.querySelector('.item-text').addEventListener('click', () => { + this.list.selectRequest.updateWithAction(this); + }); +{{< / highlight >}} + +`selectRequest` updates with the list item that was clicked as its `.value`. + +Inside `ListExtent` we add the related resources and a corresponding behavior. + +{{< highlight javascript "hl_lines=3-4">}} + this.allItems = this.state([]); + this.removeItem = this.moment(); + this.selectRequest = this.moment(); + this.selected = this.state(null); +{{< / highlight >}} + +{{< highlight javascript "hl_lines=1-6">}} + this.behavior() + .supplies(this.selected) + .demands(this.selectRequest) + .runs(() => { + this.selected.update(this.selectRequest.value); + }); +{{< / highlight >}} + +Clicking on an item sets our new `selected` resource as the item that was just clicked. + +### Selected + +Now we want our items to visually reflect when they are selected. +We can do this by demanding this resource in a behavior in each `ItemExtent`. + +{{< highlight javascript "hl_lines=1-13">}} + this.behavior() + .demands(this.list.selected) + .runs(() => { + let selected = this.list.selected.value === this; + this.sideEffect(() => { + let selectedClass = 'selected' + if (selected) { + this.itemElement.classList.add(selectedClass); + } else { + this.itemElement.classList.remove(selectedClass); + } + }); + }); +{{< / highlight >}} + +When the `selected` state resource inside `ListExtent` updates, this behavior on every item will run. +They each demand `this.list.selected`. +Depending on if the item is the one that is selected we will change the UI accordingly. + +We want to refer back to the beginning where we called `.addChildLifetime(item)` inside `ListExtent`. + +{{< highlight javascript "hl_lines=">}} + let item = new ItemExtent(this.graph, this.save.value, this); + this.addChildLifetime(item); + item.addToGraph(); +{{< / highlight >}} + +This line says that the list will always be around when the item is. +This gives us permission to add `this.list.selected`, a resource in `ListExtent`, as a demand on the behavior inside each `ItemExtent`. +Behavior Graph ensures that we don't link to resources that may no longer be part of the graph and it uses lifetimes as a way to manage that. + +You can now try out this code by clicking on different items. + +Notice that we can take a list of many items and click on different ones and watch it switch. +Each time, one of those behaviors adds the 'selected' CSS class while all the rest remove the 'selected' class. +Removing a class when its already not there is valid and simplifies our logic. + +### Deselect + +Its easy enough to introduce deselecting by clicking on the already selected element. + +Inside `ListExtent` we modify our `selected` behavior. + +{{< highlight javascript "hl_lines=5-7 9">}} + this.behavior() + .supplies(this.selected) + .demands(this.selectRequest) + .runs(() => { + if (this.selected.value == this.selectRequest.value) { + this.selected.update(null); + } else { + this.selected.update(this.selectRequest.value); + } + }); +{{< / highlight >}} + +We check if the currently selected item is the one that was just clicked on and set it to `null` in that case. +This communicates that nothing should be selected. +Try running now and clicking on an item multiple times. + +### Updating The Text Field + +Now we want to introduce editing. +Let's try updating the main text field when we select an item so we can edit it. + +{{< highlight javascript "hl_lines=10-18">}} + this.behavior() + .supplies(this.selected) + .demands(this.selectRequest) + .runs(() => { + if (this.selected.value == this.selectRequest.value) { + this.selected.update(null); + } else { + this.selected.update(this.selectRequest.value); + } + + if (this.selected.justUpdated) { + this.sideEffect(() => { + let textField = document.querySelector('#new-item-text'); + textField.value = this.selected.value === null ? '' : this.selected.value.itemText.value; + let actionText = document.querySelector('#action'); + actionText.innerText = this.selected.value === null ? 'Add' : 'Edit' + }); + } + }); +{{< / highlight >}} + +Whenever `selected` updates, we run this new side effect. +It copies over the text of the item into the text field. +It also updates the UI to indicate that we are editing and not adding. + +Conversely, when `selected` updates to `null`, it puts our UI state back to an Add mode. + +### Preventing Adding + +When we are in editing mode, the save button should cause the text in our item to update. +However right now it will still create a new item. +We want to prevent that from happening when we are in editing mode. + +{{< highlight javascript "hl_lines=5">}} + this.behavior() + .supplies(this.allItems) + .demands(this.save, this.removeItem) + .runs(() => { + if (this.save.justUpdated && this.selected.traceValue === null) { + let item = new ItemExtent(this.graph, this.save.value, this); + this.addChildLifetime(item); + item.addToGraph(); + this.allItems.value.push(item); +{{< / highlight >}} + +At the time we click the Save button, we want to know if we are in editing mode or not. +We could check `selected.value` to see if it is null (ie not editing). +However, here we use `selected.traceValue` instead. +`.traceValue` is the value of the resource at the beginning of the graph event (the instant the action started). +So if `selected` updates this event, `.traceValue` will still return what it was before it changed. + +This also removes the requirement that we demand `selected` in this behavior. +Here we just care if an item is already selected or not, not that something was "just selected". +So we don't need it as a demand. +`.traceValue` of any resource is always accessible by any behavior without demanding (or supplying) it. + +The `if` check ignores the `save` click when there's something already selected. + +### Making Changes + +Now we can add a new behavior inside `ListExtent` that responds to our save and updates the text of the selected item. + +{{< highlight javascript "hl_lines=4-14">}} + } + }); + + this.behavior() + .dynamicSupplies([this.allItems], () => { + return this.allItems.value.map(item => item.itemText); + }) + .demands(this.save) + .runs(() => { + if (this.save.justUpdated && this.selected.traceValue !== null) { + this.selected.traceValue.itemText.update(this.save.value); + } + }); + + this.behavior() + .demands(this.allItems, this.addedToGraph) +{{< / highlight >}} + +This new behavior uses `.dyanmicSupplies()`. +This is a clause we haven't seen before. +It does work similarly to `.dynamicDemands()`. +In this behavior, we update our supplies to be the `itemText` resource from each `ItemExtent` instance. +Whenever we add our remove an item, this behavior will update its supplies. + +We will supply all of them because any one of them might become selected. +When the user clicks the Save button, this behavior will update the `itemText` on the selected item to whats inside the text field. + +Notice that we use `selected.traceValue` again here, so it is not part of the demands. +We want which item was selected at the time `save` was updated. +We also do not need this behavior to run when `selected` updates. + +Notice that all we do is update `itemText`. +We already have a behavior that knows how to change that UI when we change the text. +It is common to make these kinds of changes and see everything work as expected. + +Run the code and you will see your working todo list. + +## Challenge + +After saving our changes, the item remains selected. +It might be a better user experience to exit editing mode after saving. +Can you implement this? + +Try your best before looking at the answer. + +Hints: +1. You can do this by modifying a single behavior. +2. Which behavior is responsible for `selected`? +3. Which resource updates when we click the Save button? + +### Answer: Clearing Post Save + +We can modify our `selected` behavior inside `ListExtent`. + +{{< highlight javascript "hl_lines=3 5 11-13">}} + this.behavior() + .supplies(this.selected) + .demands(this.selectRequest, this.save) + .runs(() => { + if (this.selectRequest.justUpdated) { + if (this.selected.value == this.selectRequest.value) { + this.selected.update(null); + } else { + this.selected.update(this.selectRequest.value); + } + } else if (this.save.justUpdated) { + this.selected.update(null); + } +{{< / highlight >}} + +Now our `selected` behavior also runs and deselects the current item when the Save button is pressed. +Here see again the common pattern of checking various resources' `.justUpdated` property inside a behavior. + +Just before adding this feature we used `selected.traceValue` in a few behaviors. +This change here is an additional motivation for that. +If we used `selected.value` in those behaviors it means they would demand `selected` which is supplied by this behavior. +Which means they would run _after_ this behavior. +Which means by they time they ran, `selected.value` would be null. +We don't want what `selected` changes to, we want what it was at the start. +This is what `traceValue` provides. + +## Congratulations + +Congratulations! You have completed the third tutorial. +You can see the [finished tutorial code here](https://jsfiddle.net/slevin11/vdu25ar9/). diff --git a/doc-site/content/en/why-behavior-graph.md b/doc-site/content/en/why-behavior-graph.md new file mode 100644 index 0000000..ebfe37b --- /dev/null +++ b/doc-site/content/en/why-behavior-graph.md @@ -0,0 +1,95 @@ +--- +title: "Why Behavior Graph?" +weight: 20 +--- + +**Behavior Graph** is a software library that greatly enhances our ability to program **user facing software** and **control systems**. Programs of this type quickly scale up in complexity as features are added. Behavior Graph directly addresses this complexity by shifting more of the burden to the computer. +It works by offering the programmer a new unit of code organization called a **behavior**. +Behaviors are blocks of code enriched with additional information about their stateful relationships. +Using this information, Behavior Graph enforces _safe use of mutable state_, arguably the primary source of complexity in this class of software. +It does this by taking on the responsibility of control flow between behaviors, ensuring they are are _run at the correct time and in the correct order_. + +## Interactive Systems + +It helps to understand why user facing software, control systems, and similar programs present a particular challenge. + +We define these systems by three primary characteristics: + +1. *Asynchronous*: inputs can happen over a period of time and at any time +2. *Event-driven*: outputs occur over time in response to inputs +3. *Stateful*: outputs depend on a history of prior inputs + +A thermostat controlling the temperature in a house is an example: + +![Thermostat]({{< static "images/thermostat-wall.svg" >}}) + +1. It runs continuously, responding to temperature changes as well as button presses in order to operate the heating equipment. +2. Button presses will result in changes to the display. +3. Button presses which set the desired temperature will determine when the heating equipment turns on in the future. + +The challenge comes from the large number of different inputs where order and history matter. +A sequence of 10 presses on our Up and Down buttons can occur in over 1000 different ways. +An interface that accepts 10 different types of input over a sequence of 10 events means we are facing 10 billion possible arrangements. +And that is a tiny fraction of what a real user facing application is typically up against. + +The solution comes from the fact that we only need to remember just enough information to make decisions in the future. +Instead of remembering each button press, we simply remember a desired temperature and update it as inputs happen. +We don't care which sequence of button presses gets us to 68 degrees. +To our program they are all the same. +We call this compressed historical information *state.* +With state we can compress 10 billion button presses into a single number. + +Inputs lead to state changes. +Pressing the Up and Down button changes the desired temperature state. +State changes lead to outputs. +Changing the desired temperature means the display will change. +State changes also often lead to other state changes as our program grows in features. +When the desired temperature changes, the desired state of the heating equipment may change. +(And when that desired state of the heating equipment changes, our program will output to turn on or off the heating equipment.) + +A correctly functioning program will have a natural dependency graph between inputs, internal states, and outputs. +Unfortunately, status quo programming techniques have no way of expressing this dependency graph directly. +Programmers must implicitly build this graph out of the correct sequencing of method calls and state updates. +In so doing, they throw away this valuable dependency information and the computer can no longer help us. +**That is the root of the problem.** + +## Behavior Graph + +With Behavior Graph, we build our programs out of units of functionality called *behaviors*. +Behaviors manage state via components called *resources*. +Behaviors are simple, easily understood blocks of code paired with any relationships to these resources. +Resources are objects which encapsulate both state and how that state changes. +A behavior for our thermostat would be "_when the user presses the *Up* or *Down* buttons, increase or decrease the desired temperature by one degree_." +The _desired temperature_ is the resource that this behavior manages. + +![Desired Temperature]({{< static "images/thermostat-temp.svg" >}}) + +An entire thermostat program would be built out of many of these behaviors. +So we add a second behavior, "_when the current temperature is below the desired temperature, turn on the heating equipment_." +Our behaviors will collaborate to implement the complete thermostat functionality without knowing about each other directly. +Instead, behaviors compose via resources, in this case _desired temperature_. +The first behavior declares that it is responsible for setting the _desired temperature_. +The second behavior declares that it uses the _desired temperature_ to know if it needs to turn on the heat. + +![Heating]({{< static "images/thermostat-heat.svg" >}}) + +We never run behaviors directly by calling them like we do with methods. +Instead Behavior Graph uses the dependencies between behaviors and resources to determine which behaviors need to run and in which order. +If the user presses the Up button to raise the desired temperature above the current temperature, the heating behavior will automatically run after the temperature behavior updates the _desired temperature_ resource. + +Here we can see the contrast to the status quo approach of nesting chains of method calls. +In order to ensure the heat can be turned on when the up button is pressed, the button press method needs to call the desired temperature setting method. +And that method in turn needs to call the heating equipment method. +Because no method runs unless another method calls it, we must explicitly weave these threads of control flow throughout our code. +In large programs, separately maintaining control flow to ensure our dependency graph is respected is both difficult and error prone. + +Fred Brooks [famously pointed out](https://en.wikipedia.org/wiki/No_Silver_Bullet) that software is necessarily complex because the problems themselves are complex. +With Behavior Graph we overcome our human complexity limits by delegating more of that work to the computer itself. +As programmers, we focus on individual behaviors and their immediate relationships. +The computer in turn handles the complex chore of sorting through hundreds or thousands of those behaviors to ensure a working program. + +__Behavior Graph gives us control flow for free.__ + +Behavior Graph is a compact and mature library with no external dependencies. +It is used in production applications with millions of daily users. +It is available for multiple languages and platforms (Objective C/Swift, Typescript/Javascript, Kotlin). diff --git a/doc-site/data/terms.yaml b/doc-site/data/terms.yaml new file mode 100644 index 0000000..7b01b55 --- /dev/null +++ b/doc-site/data/terms.yaml @@ -0,0 +1,167 @@ +objc: + sourcedir: "./examples/objc/BGExamples" + source-language: "objectivec" + false-bool: "@NO" + true-bool: "@YES" + resource-class: "BGResource" + state-class: "BGState" + moment-class: "BGMoment" + extent-class: "BGExtent" + graph-class: "BGGraph" + event-class: "BGEvent" + action-method: "action" + sideeffect-method: "sideEffect:" + addtograph-method: "addToGraph" + behavior-method: "behaviorWithDemands:" + update-method: "updateValue:" + omentupdate-method: "update" + momentjustupdated-method: "justUpdated" + statejustupdated-method: "justUpdated" + statejustupdatedto-method: "justUpdatedTo:" + statejustupdatedtofrom-method: "justUpdatedTo:from:" + asyncaction-method: "action:requireSync:NO" + dateprovider-property: "dateProvider" + dateprovider-class: "BGDateProvider" + example-loginextent: "LoginExtent.m" + example-loginextent-header: "LoginExtent.h" + example-loginpage: "LoginPageViewController.m" + example-chat-chat: "ChatExtent.m" + example-chat-chat-header: "ChatExtent.h" + example-chat-participant: "ParticipantExtent.m" + example-chat-participant-header: "ParticipantExtent.h" + constructor: "initializer" + string-class: "NSString" + source-resource-1: "Lines 5 and 6" + source-sideeffect-1: "Line 9" + source-statemanagement-1: "Line 8" + source-justupdated-1: "Line 11" + source-justupdated-2: "Line 18" + source-tracevalue-1: "Line 9" + source-sideeffect-1: "Line 10" + source-sideeffect-2: "line 20" + source-serialize-1: "Line 21" + source-serialize-2: "line 23" + source-serialize-3: "line 19" + source-async: "Line 4" + source-addtograph-1: "line 9" + source-addtograph-2: "Line 19" + source-extentcollections-1: "lines 12 and 20" + source-extentcollections-2: "lines 13 and 21" + source-dynamic-1: "line 8" + source-dynamic-2: "lines 5 and 6" + source-dynamic-3: "line 10" + uses-crtp: false + readme-doc: "readme-objc.html" + guide-doc: "objc.html" + github-project: "bgobjc" +typescript: + sourcedir: "./examples/typescript/BGExamples" + source-language: "typescript" + false-bool: "false" + true-bool: "true" + resource-class: "Resource" + state-class: "State" + moment-class: "Moment" + extent-class: "Extent" + graph-class: "Graph" + event-class: "GraphEvent" + action-method: "action" + sideeffect-method: "sideEffect" + addtograph-method: "addToGraph" + behavior-method: "makeBehavior" + update-method: "update" + momentupdate-method: "update" + momentjustupdated-method: "justUpdated" + statejustupdated-method: "justUpdated" + statejustupdatedto-method: "justUpdatedTo" + statejustupdatedtofrom-method: "justUpdatedToFrom" + asyncaction-method: "actionAsync" + dateprovider-property: "dateProvider" + dateprovider-class: "BehaviorGraphDateProvider" + example-loginextent: "LoginExtent.ts" + example-loginextent-header: "LoginExtent.ts" + example-loginpage: "LoginExtent.ts" + example-chat-chat: "ChatExample.ts" + example-chat-chat-header: "ChatExample.ts" + example-chat-participant: "ChatExample.ts" + example-chat-participant-header: "ChatExample.ts" + constructor: "constructor" + string-class: "string" + source-resource-1: "Lines 2 and 3" + source-sideeffect-1: "Line 6" + source-statemanagement-1: "Line 5" + source-justupdated-1: "Line 9" + source-justupdated-2: "Line 17" + source-tracevalue-1: "Line 7" + source-sideeffect-1: "Line 7" + source-sideeffect-2: "line 18" + source-serialize-1: "Line 19" + source-serialize-2: "line 21" + source-serialize-3: "line 18" + source-async: "Line 3" + source-addtograph-1: "line 8" + source-addtograph-2: "Line 17" + source-extentcollections-1: "lines 10 and 18" + source-extentcollections-2: "lines 11 and 19" + source-dynamic-1: "line 6" + source-dynamic-2: "lines 4 and 5" + source-dynamic-3: "line 9" + readme-doc: "readme-typescript.html" + guide-doc: "typescript.html" + github-project: "bgjs" +kotlin: + sourcedir: "./examples/kotlin/BGExamples" + source-language: "kotlin" + false-bool: "false" + true-bool: "true" + resource-class: "Resource" + state-class: "State" + moment-class: "Moment" + extent-class: "Extent" + graph-class: "Graph" + event-class: "GraphEvent" + action-method: "action" + sideeffect-method: "sideEffect" + addtograph-method: "addToGraph" + behavior-method: "makeBehavior" + update-method: "update" + momentupdate-method: "update" + momentjustupdated-method: "justUpdated" + statejustupdated-method: "justUpdated" + statejustupdatedto-method: "justUpdatedTo" + statejustupdatedtofrom-method: "justUpdatedToFrom" + asyncaction-method: "actionAsync" + dateprovider-property: "dateProvider" + dateprovider-class: "BehaviorGraphDateProvider" + example-loginextent: "LoginExtent.kt" + example-loginextent-header: "LoginExtent.kt" + example-loginpage: "LoginExtent.kt" + example-chat-chat: "ChatExample.kt" + example-chat-chat-header: "ChatExample.kt" + example-chat-participant: "ChatExample.kt" + example-chat-participant-header: "ChatExample.kt" + constructor: "init" + string-class: "String" + source-resource-1: "Lines 2 and 3" + source-sideeffect-1: "Line 6" + source-statemanagement-1: "Line 5" + source-justupdated-1: "Line 9" + source-justupdated-2: "Line 17" + source-tracevalue-1: "Line 7" + source-sideeffect-1: "Line 7" + source-sideeffect-2: "line 18" + source-serialize-1: "Line 19" + source-serialize-2: "line 21" + source-serialize-3: "line 18" + source-async: "Line 3" + source-addtograph-1: "line 8" + source-addtograph-2: "Line 17" + source-extentcollections-1: "lines 10 and 18" + source-extentcollections-2: "lines 11 and 19" + source-dynamic-1: "line 6" + source-dynamic-2: "lines 4 and 5" + source-dynamic-3: "line 9" + uses-crtp: false + readme-doc: "readme-kotlin.html" + guide-doc: "kotlin.html" + github-project: "bgkotlin" diff --git a/doc-site/deploy.sh b/doc-site/deploy.sh new file mode 100755 index 0000000..a2c28f6 --- /dev/null +++ b/doc-site/deploy.sh @@ -0,0 +1,17 @@ +#Copyright 2018 Google LLC +# +#Licensed under the Apache License, Version 2.0 (the "License"); +#you may not use this file except in compliance with the License. +#You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +#Unless required by applicable law or agreed to in writing, software +#distributed under the License is distributed on an "AS IS" BASIS, +#WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +#See the License for the specific language governing permissions and +#limitations under the License. +# +rm -rf public/ +HUGO_ENV="production" hugo --gc || exit 1 +s3deploy -source=public/ -region=eu-west-1 -bucket=bep.is -distribution-id=E8OKNT7W9ZYZ2 -path temp/td diff --git a/doc-site/docker-compose.yaml b/doc-site/docker-compose.yaml new file mode 100644 index 0000000..e8f211a --- /dev/null +++ b/doc-site/docker-compose.yaml @@ -0,0 +1,13 @@ +version: "3.3" + +services: + + site: + image: docsy/docsy-example + build: + context: . + command: server + ports: + - "1313:1313" + volumes: + - .:/src diff --git a/doc-site/examples/kotlin/.gitignore b/doc-site/examples/kotlin/.gitignore new file mode 100644 index 0000000..c6ef218 --- /dev/null +++ b/doc-site/examples/kotlin/.gitignore @@ -0,0 +1,2 @@ +.idea + diff --git a/doc-site/examples/kotlin/BGExamples/ChatExample.kt b/doc-site/examples/kotlin/BGExamples/ChatExample.kt new file mode 100644 index 0000000..15f4791 --- /dev/null +++ b/doc-site/examples/kotlin/BGExamples/ChatExample.kt @@ -0,0 +1,156 @@ +import com.yahoo.behaviorgraph.* + +// @tag::chat_extent[] +class ChatExtent(graph: Graph) : Extent(graph) { +// @end::chat_extent[] + + val participantJoined: Moment + val participantDisconnected: Moment + + // @tag::chat_participants_resources[] + val participants: State> + // @end::chat_participants_resources[] + + val pinnedParticipant: State + + val participantsRelink: Resource + + init { + + // tag::participants[] + this.participantJoined = Moment(this) + this.participantDisconnected = Moment(this) + this.participants = State(this, mutableMapOf()) + this.makeBehavior(listOf(this.participantJoined, this.participantDisconnected), listOf(this.participants)) { extent -> + if (extent.participantJoined.justUpdated) { + val participantId = extent.participantJoined.value + val participant = ParticipantExtent(extent.graph, participantId, extent) + participant.addToGraph() + extent.participants.value.set(participantId, participant) + extent.participants.update(extent.participants.value, false) + } + + if (extent.participantDisconnected.justUpdated) { + val participantId = extent.participantDisconnected.value + val participant = extent.participants.value[participantId] + participant!!.removeFromGraph() + extent.participants.value.remove(participantId) + extent.participants.update(extent.participants.value, false) + + } + + } + // end::participants[] + + // tag::chat_relink_pinned[] + participantsRelink = Resource(this) + makeBehavior(listOf(participants), listOf(participantsRelink)) { extent -> + val demands = mutableListOf() + demands.add(extent.participants) + demands.add(extent.participantsRelink) + extent.participants.value.values.forEach { + demands.add(it.pinTap) + } + extent.pinnedParticipant.suppliedBy!!.setDemands(demands) + } + // end::chat_relink_pinned[] + + // tag::chat_pinned[] + pinnedParticipant = State(this, null) + makeBehavior(listOf(this.participants, this.participantsRelink), listOf(this.pinnedParticipant)) { chatExtent -> + val currentPinned = chatExtent.pinnedParticipant.value + var newPinned: ParticipantExtent? = null + for (particpantExtent in chatExtent.participants.value.values) { + if (particpantExtent.pinTap.justUpdated) { + newPinned = particpantExtent + break + } else if (particpantExtent == currentPinned) { + newPinned = currentPinned + } + } + + chatExtent.pinnedParticipant.update(newPinned, true) + } + // end::chat_pinned[] + + + } +} + +// @tag::participant_extent[] +class ParticipantExtent( + graph: Graph, + participantId: String, + chatExtent: ChatExtent + +) : Extent(graph) { +// @end::participant_extent[] + + val chatExtent: ChatExtent + // @tag::participant_mute_resources[] + val muteTap: Moment + val muted: State + // @end::participant_mute_resources[] + + // @tag::participant_pin_resources[] + val pinTap: Moment + // @end::participant_pin_resources[] + val participantId: String + + init{ + this.participantId = participantId + this.chatExtent = chatExtent + + this.pinTap = Moment(this) + + // tag::participant_mute[] + this.muteTap = Moment(this) + this.muted = State(this, false) + this.makeBehavior(listOf(this.muteTap), listOf(this.muted)){ extent -> + if (extent.muteTap.justUpdated) { + extent.muted.update(extent.muted.value, true) + if (extent.muted.justUpdated) { + extent.sideEffect("mute toggle") { extent -> + + extent.muteParticipant(extent.muted.value) + extent.updateMuteUI(extent.muted.value) + } + } + } + } + // end::participant_mute[] + + /* + // tag::participant_mute_alt[] + this.muteBehavior = this.makeBehavior(listOf(this.muteTap), listOf(this.muted), //... + // end::participant_mute_alt[] + */ + + // tag::participant_pinned[] + this.makeBehavior(listOf(this.chatExtent.pinnedParticipant), null) { participantExtent -> + if (participantExtent.chatExtent.pinnedParticipant.justUpdatedTo(participantExtent)) { + participantExtent.sideEffect("show as pinned") { + it.updatePinUI(true) + } + } else if (participantExtent.chatExtent.pinnedParticipant.justUpdatedFrom(participantExtent)) { + participantExtent.sideEffect("show as normal") { + it.updatePinUI(false) + } + } + } + // end::participant_pinned[] + + } + + fun updatePinUI(pinned: Boolean) { + // update UI + } + + fun updateMuteUI(mute: Boolean) { + // update UI + } + + fun muteParticipant(mute: Boolean) { + // external api call + } +} \ No newline at end of file diff --git a/doc-site/examples/kotlin/BGExamples/LoginExtent.kt b/doc-site/examples/kotlin/BGExamples/LoginExtent.kt new file mode 100644 index 0000000..af5cb64 --- /dev/null +++ b/doc-site/examples/kotlin/BGExamples/LoginExtent.kt @@ -0,0 +1,287 @@ +import com.yahoo.behaviorgraph.Extent +import com.yahoo.behaviorgraph.Graph +import com.yahoo.behaviorgraph.Moment +import com.yahoo.behaviorgraph.State + +// tag::login_enable_extent[] +class LoginExtent(graph: Graph) : Extent(graph) { + val email: State + val password: State +// end::login_enable_extent[] + + val loggingIn = State(this, false) + val emailValid = State(this, false) + val passwordValid = State(this, false) + val loginEnabled = State(this, false) + val loginClick = Moment(this) + val returnKey = Moment(this) + val loginComplete = Moment(this) + + // tag::login_enable_init[] + init { + + this.email = State(this, "") + this.password = State(this, "") + + // tag::login_enable_behavior[] + this.makeBehavior(listOf(email, password), null) { loginExtent -> + // end::login_enable_init[] + val email = loginExtent.email.value + val password2: String = loginExtent.password.value + val hasPassword = password2.length > 0 + val loginEnabled = loginExtent.validEmailAddress(email) && hasPassword + loginExtent.sideEffect("enable login button") { + loginExtent.enableLoginButton(loginEnabled) + } + } + // end::login_enable_behavior[] + } + + + fun validEmailAddress(email: String) : Boolean { + return (email.length > 0) && email.includes('@') + } + + fun doLogin(email: String, password: String, complete: (Boolean) -> Unit) { + // login api calls + } + + fun enableLoginButton(enabled: Boolean) { + // side effect to set the enabled state of the login button + } + + // tag::login_sequence_compare[] + fun emailChangedSincePassword() : Boolean { + return this.email.event.sequence > this.password.event.sequence + } + // end::login_sequence_compare[] + + // tag::login_timestamp[] + fun loginCompletedWhen() : Long { + return this.loginComplete.event!!.timestamp + } + // end::login_timestamp[] + + +} +class LoginCompleteExtent(graph: Graph) : Extent(graph) { + val email = State(this, "") + val password = State(this, "") + + val loggingIn = State(this, false) + val emailValid = State(this, false) + val passwordValid = State(this, false) + + //begin complete constructor + + init { + + // tag::login_complete_email[] + val emailValid = State(this, false) + makeBehavior(listOf(email), listOf(emailValid)) { loginExtent -> + val email = loginExtent.email.value + val emailValid = loginExtent.validEmailAddress(email) + loginExtent.emailValid.update(emailValid, true) + } + // end::login_complete_email[] + + makeBehavior(listOf(password), listOf(passwordValid)) { loginExtent -> + val password = loginExtent.password.value + val passwordValid = password.length > 0 + loginExtent.passwordValid.update(passwordValid, true) + } + + // tag::login_complete_enable[] + val loginEnabled = State(this, false) + makeBehavior(listOf(emailValid, passwordValid, loggingIn), listOf(loginEnabled)) { loginExtent -> + val enabled = loginExtent.emailValid.value && loginExtent.passwordValid.value && !loginExtent.loggingIn.value; + loginExtent.loginEnabled.update(enabled, true); + loginExtent.sideEffect("enable login button") { loginExtent -> + loginExtent.enableLoginButton(loginExtent.loginEnabled.value); + } + } + // end::login_complete_enable[] + + // tag::login_complete_login[] + val loginClick = Moment(this) + val returnKey = Moment(this) + val loginComplete = Moment(this) + makeBehavior(listOf(loginClick, returnKey, loginComplete), listOf(this.loggingIn)) { loginExtent -> + if ((loginExtent.loginClick.justUpdated || loginExtent.returnKey.justUpdated) && + loginExtent.loginEnabled.traceValue) { + // Start login + loginExtent.loggingIn.update(true, true); + } else if (loginExtent.loginComplete.justUpdated && + !loginExtent.loginComplete.value && + loginExtent.loggingIn.value) { + // Login failed + loginExtent.loggingIn.update(false, true); + } + + if (loginExtent.loggingIn.justUpdatedTo(true)) { + loginExtent.sideEffect("login api call") { + it.doLogin(it.email.value, it.password.value) { success -> + it.action("login call returned") { + it.loginComplete.update(success); + } + } + } + } + } + // end::login_complete_login[] + + // Dont delete; its used in the documentation + // this has an example of requireSync + /* + makeBehavior(listOf(loginClick, returnKey, loginComplete), listOf(loggingIn)) { extent -> + if ((extent.loginClick.justUpdated || extent.returnKey.justUpdated) && + extent.loginEnabled.traced.value) { + // Start login + extent.loggingIn.update(true, true) + } else if (extent.loginComplete.justUpdated && + !extent.loginComplete.value && + extent.loggingIn.value) { + // Login failed + extent.loggingIn.update(false, true) + } + + if (extent.loggingIn.justUpdatedTo(true)) { + // tag::login_complete_loginalt[] + extent.sideEffect("login api call") { + it.doLogin(extent.email.value, extent.password.value) { success -> + it.actionAsync("login call returned") { + it.loginComplete.update(success) + }) + }) + }) + // end::login_complete_loginalt[] + } + }) + */ + + } + + + //end complete constructor + + + fun validEmailAddress(email: String) : Boolean { + return (email.length > 0) && email.includes('@') + } + + fun doLogin(email: String, password: String, complete: (Boolean) -> Unit) { + // login api calls + } + + fun enableLoginButton(enabled: Boolean) { + // side effect to set the enabled state of the login button + } + +} + +class LoginShortExtent { + val email = State(this, "") + val password = State(this, "") + + val loggingIn = State(this, false) + val emailValid = State(this, false) + val passwordValid = State(this, false) + + init { + // tag::login_intro_short1[] + makeBehavior(listOf(email, password), listOf(loginEnabled)) { extent -> + + val emailValid = extent.validEmailAddress(email.value) + val passwordValid = extent.password.value.length > 0 + val enabled = emailValid && passwordValid + extent.loginEnabled.update(enabled) + + }; + // end::login_intro_short1[] + + + // tag::login_intro_short2[] + makeBehavior(listOf(loginClick), listOf(loggingIn)) { extent -> + + if (extent.loginClick.justUpdated && !extent.loggingIn.value) { + extent.loggingIn.update(true); + } + + } + + makeBehavior(listOf(email, password, loggingIn), listOf(loginEnabled)) { extent -> + + val emailValid = extent.validEmailAddress(email.value) + val passwordValid = extent.password.value.length > 0 + val enabled = emailValid && passwordValid && !extent.loggingIn.value + extent.loginEnabled.update(enabled) + + }; + // end::login_intro_short2[] + + // tag::login_intro_sideeffect[] + makeBehavior(listOf(email, password, loggingIn), listOf(loginEnabled)) { extent -> + + val emailValid = extent.validEmailAddress(email.value) + val passwordValid = extent.password.value.length > 0 + val enabled = emailValid && passwordValid && !extent.loggingIn.value + extent.loginEnabled.update(enabled) + + extent.sideEffect("login button enabled") { extent -> + extent.loginButton.enabled = extent.loginEnabled.value; + } + + }; + // end::login_intro_sideeffect[] + + } + + // tag::login_intro_action[] + fun loginButtonClicked() { + this.graph.action("login button clicked") { + this.loginClick.update(Unit) + } + } + // end::login_intro_action[] + +} + +class LoginPage { + + val graph: Graph + val loginExtent: LoginExtent + + init { + // tag::login_enable_setup[] + this.graph = Graph() + this.loginExtent = LoginExtent(graph) + this.graph.action("new login page") { + this.loginExtent.addToGraph() + } + // end::login_enable_setup[] + } + + // tag::login_enable_actions[] + fun didUpdateEmailField(contents: String) { + this.graph.action("update email field") { + this.loginExtent.email.update(contents, true) + } + } + + fun didUpdatePasswordField(contents: String) { + this.graph.action("update password field") { + this.loginExtent.password.update(contents, true) + } + } + // end::login_enable_actions[] + + // tag::login_complete_click[] + fun loginButtonClicked() { + this.graph.action("login button clicked") { + this.loginExtent.loginClick.update(Unit) + } + } + // end::login_complete_click[] + + +} diff --git a/doc-site/examples/kotlin/BGExamples/com/yahoo/behaviorgraph/Action.kt b/doc-site/examples/kotlin/BGExamples/com/yahoo/behaviorgraph/Action.kt new file mode 100644 index 0000000..9982496 --- /dev/null +++ b/doc-site/examples/kotlin/BGExamples/com/yahoo/behaviorgraph/Action.kt @@ -0,0 +1,3 @@ +package com.yahoo.behaviorgraph + +internal class Action(val impulse: String?, val block: () -> Unit) diff --git a/doc-site/examples/kotlin/BGExamples/com/yahoo/behaviorgraph/Behavior.kt b/doc-site/examples/kotlin/BGExamples/com/yahoo/behaviorgraph/Behavior.kt new file mode 100644 index 0000000..76d3fbc --- /dev/null +++ b/doc-site/examples/kotlin/BGExamples/com/yahoo/behaviorgraph/Behavior.kt @@ -0,0 +1,39 @@ +package com.yahoo.behaviorgraph + +class Behavior( + val extent: Extent<*>, demands: List?, supplies: List?, + var block: (Extent<*>) -> Unit +) : Comparable { + var demands: MutableSet? = null + var supplies: MutableSet? = null + var debugName: String? = null + var enqueuedWhen: Long? = null + var removedWhen: Long? = null + var added = false + internal var orderingState = OrderingState.Unordered + var order: Long = 0 + var untrackedDemands: List? + var untrackedSupplies: List? + + init { + extent.addBehavior(this) + this.untrackedDemands = demands + this.untrackedSupplies = supplies + } + + override fun compareTo(other: Behavior): Int { + return order.compareTo(other.order) + } + + override fun toString(): String { + return "Behavior(debugName=$debugName)" + } + + fun setDemands(newDemands: List) { + this.extent.graph.updateDemands(this, newDemands) + } + + fun setSupplies(newSupplies: List) { + this.extent.graph.updateSupplies(this, newSupplies) + } +} diff --git a/doc-site/examples/kotlin/BGExamples/com/yahoo/behaviorgraph/Event.kt b/doc-site/examples/kotlin/BGExamples/com/yahoo/behaviorgraph/Event.kt new file mode 100644 index 0000000..fa1b1db --- /dev/null +++ b/doc-site/examples/kotlin/BGExamples/com/yahoo/behaviorgraph/Event.kt @@ -0,0 +1,7 @@ +package com.yahoo.behaviorgraph + +data class Event(val sequence: Long, val timestamp: Long, val impulse: String?) { + companion object { + val InitialEvent: Event = Event(0, 0, "InitialEvent") + } +} diff --git a/doc-site/examples/kotlin/BGExamples/com/yahoo/behaviorgraph/Extent.kt b/doc-site/examples/kotlin/BGExamples/com/yahoo/behaviorgraph/Extent.kt new file mode 100644 index 0000000..5f10227 --- /dev/null +++ b/doc-site/examples/kotlin/BGExamples/com/yahoo/behaviorgraph/Extent.kt @@ -0,0 +1,97 @@ +package com.yahoo.behaviorgraph + +import com.yahoo.behaviorgraph.exception.BehaviorGraphException +import kotlin.system.measureTimeMillis + +/** + * A container for a group of related behaviors and resources + */ +open class Extent(val graph: Graph) { //TODO restrict SubclassType to subclass of Extent + var debugName: String = javaClass.simpleName + internal var behaviors: MutableList = mutableListOf() + internal var resources: MutableList = mutableListOf() + var addedToGraphWhen: Event? = null + internal set + + fun addBehavior(behavior: Behavior) { + this.behaviors.add(behavior) + } + + fun addResource(resource: Resource) { + this.resources.add(resource) + } + + fun addToGraphWithAction() { + this.graph.action("add extent: $debugName") { this.addToGraph() } + } + + fun addToGraph() { + if (graph.currentEvent != null) { + nameResources() + graph.addExtent(this) + } else { + throw BehaviorGraphException("addToGraph must be called within an event. Extent=$this") + } + } + + fun removeFromGraphWithAction() { + this.graph.action("remove extent: $debugName") { this.removeFromGraph() } + } + + fun removeFromGraph() { + if (graph.currentEvent != null) { + if (addedToGraphWhen != null) { + graph.removeExtent(this) + } + } else { + throw BehaviorGraphException("removeFromGraph must be called within an event. Extent=$this") + } + } + + fun makeBehavior( + demands: List?, + supplies: List?, + block: (SubclassType) -> Unit + ): Behavior { + return Behavior(this, demands, supplies, block as (Extent<*>) -> Unit) + } + + fun sideEffect(name: String?, block: (extent: SubclassType) -> Unit) { + graph.sideEffect(this, name, block as (Extent<*>) -> Unit) + } + + fun actionAsync(impulse: String?, action: () -> Unit) { + if (this.addedToGraphWhen != null) { + this.graph.actionAsync(impulse, action) + } else { + throw BehaviorGraphException("Action on extent requires it be added to the graph. Extent=$this") + } + } + + fun action(impulse: String?, action: () -> Unit) { + if (this.addedToGraphWhen != null) { + this.graph.action(impulse, action) + } else { + throw BehaviorGraphException("Action on extent requires it be added to the graph. Extent=$this") + } + } + + /** + * Ensure all resources in self (not superclasses) have a debugName. + * future: move to platformSupport since this is not portable beyond the jvm + */ + private fun nameResources() { + val timeMS = measureTimeMillis { + javaClass.declaredFields.forEach { field -> + if (field.type == Resource::class.java) { + val resource = field.get(this) as Resource + if (resource.debugName == null) { + println("setting debugName for ${field.name}") + resource.debugName = field.name + } + } + } + } + println("collectAndNameResources() time was $timeMS ms") + } +} diff --git a/doc-site/examples/kotlin/BGExamples/com/yahoo/behaviorgraph/Graph.kt b/doc-site/examples/kotlin/BGExamples/com/yahoo/behaviorgraph/Graph.kt new file mode 100644 index 0000000..835a3a0 --- /dev/null +++ b/doc-site/examples/kotlin/BGExamples/com/yahoo/behaviorgraph/Graph.kt @@ -0,0 +1,472 @@ +package com.yahoo.behaviorgraph + +import com.yahoo.behaviorgraph.Event.Companion.InitialEvent +import com.yahoo.behaviorgraph.exception.AllDemandsMustBeAddedToTheGraphExceptions +import com.yahoo.behaviorgraph.exception.BehaviorDependencyCycleDetectedException +import com.yahoo.behaviorgraph.exception.BehaviorGraphException +import com.yahoo.behaviorgraph.exception.ExtentsCanOnlyBeAddedDuringAnEventException +import com.yahoo.behaviorgraph.exception.ExtentsCanOnlyBeRemovedDuringAnEventException +import com.yahoo.behaviorgraph.exception.ResourceCannotBeSuppliedByMoreThanOneBehaviorException +import com.yahoo.behaviorgraph.platform.PlatformSupport +import java.util.ArrayDeque +import java.util.ArrayList +import java.util.Deque +import java.util.HashSet +import java.util.PriorityQueue +import kotlin.math.max + +class Graph constructor(private var platformSupport: PlatformSupport = PlatformSupport.platformSupport) { + internal var currentEvent: Event? = null + var lastEvent: Event + private var activatedBehaviors: PriorityQueue + internal var currentBehavior: Behavior? = null + private var effects: Deque + private var actions: Deque + private var untrackedBehaviors: MutableList + private var modifiedDemandBehaviors: MutableList + private var modifiedSupplyBehaviors: MutableList + private var updatedTransients: MutableList + private var needsOrdering: MutableList + + init { + effects = ArrayDeque() + actions = ArrayDeque() + activatedBehaviors = PriorityQueue() + untrackedBehaviors = ArrayList() + modifiedDemandBehaviors = ArrayList() + modifiedSupplyBehaviors = ArrayList() + updatedTransients = ArrayList() + needsOrdering = ArrayList() + lastEvent = InitialEvent + } + + //***** + fun actionAsync(impulse: String?, block: () -> Unit) { + val action = Action(impulse, block) + this.actions.addLast(action) + if (this.currentEvent == null) { + this.eventLoop() + } + } + + fun action(impulse: String?, block: () -> Unit) { + val action = Action(impulse, block) + this.actions.addLast(action) + this.eventLoop() + } + + fun eventLoop() { + while (true) { + try { + if (this.activatedBehaviors.size > 0 || + this.untrackedBehaviors.size > 0 || + this.modifiedDemandBehaviors.size > 0 || + this.modifiedSupplyBehaviors.size > 0 || + this.needsOrdering.size > 0 + ) { + val sequence = this.currentEvent!!.sequence + this.addUntrackedBehaviors(sequence) + this.addUntrackedSupplies(sequence) + this.addUntrackedDemands(sequence) + this.orderBehaviors() + this.runNextBehavior(sequence) + + continue + } + + if (effects.isNotEmpty()) { + val effect = this.effects.removeFirst() + effect.block(effect.extent) + continue + } + + currentEvent?.let { aCurrentEvent -> + this.clearTransients() + this.lastEvent = aCurrentEvent + this.currentEvent = null + this.currentBehavior = null + } + + if (actions.isNotEmpty()) { + val action = actions.removeFirst() + val newEvent = Event( + this.lastEvent.sequence + 1, + platformSupport.getCurrentTimeMillis(), + action.impulse + ) + this.currentEvent = newEvent + action.block() + continue + } + } catch (e: Exception) { + //put graph into clean state and rethrow exception + this.currentEvent = null + this.actions.clear() + this.effects.clear() + this.currentBehavior = null + this.activatedBehaviors.clear() + this.clearTransients() + this.modifiedDemandBehaviors.clear() + this.modifiedSupplyBehaviors.clear() + this.untrackedBehaviors.clear() + throw(e) + } + // no more tasks so we can exit the event loop + break + } + } + + private fun clearTransients() { + updatedTransients.forEach { + it.clear() + } + updatedTransients.clear() + } + + internal fun trackTransient(resource: Transient) { + this.updatedTransients.add(resource) + } + + internal fun resourceTouched(resource: Resource) { + this.currentEvent?.let { aCurrentEvent -> + for (subsequent in resource.subsequents) { + this.activateBehavior(subsequent, aCurrentEvent.sequence) + } + } + } + + private fun activateBehavior(behavior: Behavior, sequence: Long) { + if (behavior.enqueuedWhen == null || behavior.enqueuedWhen!! < sequence) { + behavior.enqueuedWhen = sequence + //note addLast() versus the javascript push(), which here would add first and in javascript appends + this.activatedBehaviors.add(behavior) + } + } + + private fun runNextBehavior(sequence: Long) { + if (this.activatedBehaviors.isEmpty()) { + return + } + val behavior = this.activatedBehaviors.remove() + if (behavior.removedWhen != sequence) { + this.currentBehavior = behavior + behavior.block(behavior.extent!!) + this.currentBehavior = null + } + } + + internal fun sideEffect(extent: Extent<*>, name: String?, block: (extent: Extent<*>) -> Unit) { + if (this.currentEvent == null) { + throw BehaviorGraphException("Effects can only be added during an event loop.") + } else { + this.effects.addLast(SideEffect(name, block, extent)) + } + } + + private fun addUntrackedBehaviors(sequence: Long) { + for (behavior in this.untrackedBehaviors) { + this.activateBehavior(behavior, sequence) + this.modifiedDemandBehaviors.add(behavior) + this.modifiedSupplyBehaviors.add(behavior) + } + this.untrackedBehaviors.clear() + } + + //Note: parameter sequence not used. We'll keep because typescript uses it. + private fun addUntrackedSupplies(sequence: Long) { + modifiedSupplyBehaviors.forEach { behavior -> + behavior.untrackedSupplies?.let { behaviorUntrackedSupplies -> + behavior.supplies?.forEach { existingSupply -> + existingSupply.suppliedBy = null + } + behavior.supplies = HashSet(behaviorUntrackedSupplies) + behavior.supplies?.forEach { newSupply: Resource -> + if (newSupply.suppliedBy != null && newSupply.suppliedBy !== behavior) { + throw ResourceCannotBeSuppliedByMoreThanOneBehaviorException( + "Resource cannot be supplied by more than one behavior", + newSupply, + behavior + ) + } + newSupply.suppliedBy = behavior + } + behavior.untrackedSupplies = null + // technically this doesn't need reordering but its subsequents will + // setting this to reorder will also adjust its subsequents if necessary + // in the sortDFS code + this.needsOrdering.add(behavior) + } + } + this.modifiedSupplyBehaviors.clear() + } + + private fun addUntrackedDemands(sequence: Long) { + modifiedDemandBehaviors.forEach { behavior -> + behavior.untrackedDemands?.let { untrackedDemands -> + var removedDemands: MutableList? = null + behavior.demands?.forEach { demand -> + if (!untrackedDemands.contains(demand)) { + if (removedDemands == null) { + removedDemands = ArrayList() + } + removedDemands?.add(demand) + } + } + var addedDemands: MutableList? = null + + for (untrackedDemand in untrackedDemands) { + if (!untrackedDemand.added) { + throw AllDemandsMustBeAddedToTheGraphExceptions( + "All demands must be added to the graph.", + behavior, + untrackedDemand + ) + } + if (behavior.demands == null || !behavior.demands!!.contains(untrackedDemand)) { + if (addedDemands == null) { + addedDemands = ArrayList() + } + addedDemands.add(untrackedDemand) + } + } + var needsRunning = false + + removedDemands?.let { localRemovedDemands -> + needsRunning = true + for (demand in localRemovedDemands) { + demand.subsequents.remove(behavior) + } + } + var orderBehavior = behavior.orderingState == OrderingState.Unordered + + addedDemands?.let { localAddedDemands -> + needsRunning = true + for (demand in localAddedDemands) { + demand.subsequents.add(behavior) + + if (!orderBehavior) { + val prior = demand.suppliedBy + if (prior != null && prior.orderingState == OrderingState.Ordered && prior.order >= behavior.order) { + orderBehavior = true + } + } + } + } + + behavior.demands = HashSet(behavior.untrackedDemands) + behavior.untrackedDemands = null + + if (orderBehavior) { + this.needsOrdering.add(behavior) + } + if (needsRunning) { + this.activateBehavior(behavior, sequence) + } + } + } + this.modifiedDemandBehaviors.clear() + } + + /** + * find all behaviors that need ordering and their + // subsequents and mark them all as needing ordering + */ + private fun orderBehaviors() { + if (needsOrdering.isEmpty()) { + return + } + val localNeedsOrdering = ArrayList() + val traversalQueue = ArrayDeque() + // first get behaviors that need ordering and mark them as + // ordered so they will be traversed when first encountered + for (behavior in needsOrdering) { + behavior.orderingState = OrderingState.Ordered + traversalQueue.addLast(behavior) + } + + needsOrdering.clear() + + while (traversalQueue.isNotEmpty()) { + var behavior = traversalQueue.removeFirst() + + if (behavior.orderingState == OrderingState.Ordered) { + behavior.orderingState = OrderingState.Unordered + localNeedsOrdering.add(behavior) + behavior.supplies?.forEach { aResource -> + aResource.subsequents.forEach { aSubsequentBehavior -> + traversalQueue.push(aSubsequentBehavior) + } + } + } + } + //TODO is there a kotlin idiom for the following? + val needsReheap = mutableListOf(false) // this allows out parameter + for (behavior in localNeedsOrdering) { + this.sortDFS(behavior, needsReheap) + } + + if (needsReheap.first()) { + //we've invalidated our current activatedBehaviors by changing the priority of + //some of the behaviors, so resort. + val newActivatedBehaviors = PriorityQueue() + activatedBehaviors.forEach { + newActivatedBehaviors.add(it) + } + activatedBehaviors = newActivatedBehaviors + } + } + + private fun sortDFS(behavior: Behavior, needsReheap: MutableList) { + if (behavior.orderingState == OrderingState.Ordering) { + throw BehaviorDependencyCycleDetectedException( + "Behavior dependency cycle detected.", behavior, + cycleForBehavior(behavior) + ) + } + + if (behavior.orderingState == OrderingState.Unordered) { + behavior.orderingState = OrderingState.Ordering + var order = 0L + behavior.demands?.forEach { localResource -> + localResource.suppliedBy?.let { localBehavior -> + if (localBehavior.orderingState != OrderingState.Ordered) { + this.sortDFS(localBehavior, needsReheap) + } + order = max(order, localBehavior.order + 1) + } + } + + behavior.orderingState = OrderingState.Ordered + + if (order != behavior.order) { + behavior.order = order + needsReheap[0] = true + } + } + } + + private fun cycleForBehavior(behavior: Behavior): List { + var stack = ArrayList() //we'll "push" and "pop" from the end + if (cycleDFS(behavior, behavior, stack)) { + var output = ArrayList() + while (stack.isNotEmpty()) { + var rez = stack.removeAt(stack.size - 1) + output.add(rez) + } + return output + } else { + return ArrayList() + } + } + + private fun cycleDFS( + currentBehavior: Behavior, + target: Behavior, + stack: MutableList + ): Boolean { + currentBehavior.demands?.forEach { aResource -> + stack.add(aResource) + var b = aResource.suppliedBy + if (b != null) { + if (b == target) { + return true + } + if (this.cycleDFS(b, target, stack)) { + return true + } + stack.removeAt(stack.size - 1) + } + } + + return false + } + + private fun addBehavior(behavior: Behavior) { + behavior.added = true + this.untrackedBehaviors.add(behavior) + } + + fun updateDemands(behavior: Behavior, newDemands: List) { + if (!behavior.added) { + throw BehaviorGraphException("Behavior must belong to graph before updating demands: $behavior") + } else if (this.currentEvent == null) { + throw BehaviorGraphException("Demands can only be updated during an event loop. Behavior=$behavior") + } + behavior.untrackedDemands = newDemands + this.modifiedDemandBehaviors.add(behavior) + } + + fun updateSupplies(behavior: Behavior, newSupplies: List) { + if (!behavior.added) { + throw BehaviorGraphException("Behavior must belong to graph before updating supplies. Behavior=$behavior") + } + + this.currentEvent + ?: throw BehaviorGraphException("Supplies can only be updated during an event loop. Behavior=$behavior") + + behavior.untrackedSupplies = newSupplies + this.modifiedSupplyBehaviors.add(behavior) + } + + private fun removeBehavior(behavior: Behavior, sequence: Long) { + // remove all behaviors supplies from subsequents demands + behavior.supplies?.forEach { supply -> + supply.subsequents.forEach { subsequent -> + subsequent.demands?.remove(supply) + } + supply.subsequents.clear() + } + + behavior.demands?.forEach { demand -> + demand.subsequents.remove(behavior) + } + behavior.demands?.clear() + + + behavior.removedWhen = sequence + behavior.added = false + } + + private fun addResource(resource: Resource) { + resource.added = true + } + + fun addExtent(extent: Extent<*>) { + if (extent.addedToGraphWhen != null) { + throw BehaviorGraphException("Extent $extent has already been added to the graph: ${extent.graph}") + } + + this.currentEvent?.let { localCurrentEvent -> + extent.addedToGraphWhen = localCurrentEvent + extent.resources.forEach { + this.addResource(it) + } + extent.behaviors.forEach { + addBehavior(it) + } + } ?: run { + throw ExtentsCanOnlyBeAddedDuringAnEventException( + "Extents can only be added during an event.", + extent + ) + } + } + + fun removeExtent(extent: Extent<*>) { + this.currentEvent?.let { localCurrentEvent -> + extent.resources.forEach { resource -> + resource.added = false + } + extent.behaviors.forEach { behavior -> + removeBehavior(behavior, localCurrentEvent.sequence) + } + + extent.addedToGraphWhen = null + } ?: run { + throw ExtentsCanOnlyBeRemovedDuringAnEventException( + "Extents can only be removed during an event loop.", + extent + ) + } + } +} diff --git a/doc-site/examples/kotlin/BGExamples/com/yahoo/behaviorgraph/Moment.kt b/doc-site/examples/kotlin/BGExamples/com/yahoo/behaviorgraph/Moment.kt new file mode 100644 index 0000000..fc45ebc --- /dev/null +++ b/doc-site/examples/kotlin/BGExamples/com/yahoo/behaviorgraph/Moment.kt @@ -0,0 +1,53 @@ +package com.yahoo.behaviorgraph + +import com.yahoo.behaviorgraph.exception.BehaviorGraphException + +class Moment(extent: Extent<*>, debugName: String? = null) : Resource(extent, debugName), + Transient { + private var _happened = false + private var _happenedValue: T? = null + private var _happenedWhen: Event? = null + + /** + * return if we've just been updated + */ + val justUpdated: Boolean + get() = this._happened + + /** + * @throws BehaviorGraphException if not justUpdated()) + */ + val value: T + get() { + if (!justUpdated) { + throw BehaviorGraphException("Cannot access value unless it has been justUpdated()") + } + return this._happenedValue!! + } + val event: Event? + get() = this._happenedWhen + + fun updateWithAction(value: T) { + graph.action(getImpulse()) { update(value) } + } + + private fun getImpulse(): String? { + return if (this.debugName != null) { + "Impulse From happen(): $this)" + } else null + } + + fun update(value: T) { + this.assertValidUpdater() + this._happened = true + this._happenedValue = value + this._happenedWhen = this.graph.currentEvent + this.graph.resourceTouched(this) + this.graph.trackTransient(this) + } + + override fun clear() { + this._happened = false + this._happenedValue = null + } +} diff --git a/doc-site/examples/kotlin/BGExamples/com/yahoo/behaviorgraph/OrderingState.kt b/doc-site/examples/kotlin/BGExamples/com/yahoo/behaviorgraph/OrderingState.kt new file mode 100644 index 0000000..8028fee --- /dev/null +++ b/doc-site/examples/kotlin/BGExamples/com/yahoo/behaviorgraph/OrderingState.kt @@ -0,0 +1,7 @@ +package com.yahoo.behaviorgraph + +internal enum class OrderingState { + Unordered, + Ordered, + Ordering +} diff --git a/doc-site/examples/kotlin/BGExamples/com/yahoo/behaviorgraph/Resource.kt b/doc-site/examples/kotlin/BGExamples/com/yahoo/behaviorgraph/Resource.kt new file mode 100644 index 0000000..687ddca --- /dev/null +++ b/doc-site/examples/kotlin/BGExamples/com/yahoo/behaviorgraph/Resource.kt @@ -0,0 +1,139 @@ +package com.yahoo.behaviorgraph + +import com.yahoo.behaviorgraph.exception.BehaviorGraphException +import java.util.HashSet + +open class Resource(val extent: Extent<*>, var debugName: String? = null) { + val graph: Graph = extent.graph + var added = false + var subsequents: MutableSet = HashSet() + var suppliedBy: Behavior? = null + + init { + extent.addResource(this) + } + + internal fun assertValidUpdater() { + val currentBehavior = graph.currentBehavior + val currentEvent = graph.currentEvent + if (currentBehavior == null && currentEvent == null) { + throw BehaviorGraphException("Resource $debugName must be updated inside a behavior or action") + } + if (this.suppliedBy != null && currentBehavior != this.suppliedBy) { + throw BehaviorGraphException("Supplied resource $debugName can only be updated by its supplying behavior. CurrentBehavior = $currentBehavior") + + } + if (this.suppliedBy == null && currentBehavior != null) { + throw BehaviorGraphException("Unsupplied resource $debugName can only be updated in an action. CurrentBehavior=$currentBehavior") + } + } +} + +/* +open class Resource { + var value: T? = null + var event: Event? = null + var debugName: String? = null + var traced: Boolean = false + var valuePersistence: ValuePersistence + var previousValue: T? = null + var previousEvent: Event? = null + var graph: Graph + var added: Boolean = false + var extent: Extent? = null + var subsequents: MutableSet + var suppliedBy: Behavior? = null + var capturedUpdate: (() -> Unit)? = null + var traceValue: T? + get() { + if (!traced) { + throw BehaviorGraphException("Accessing traced value for non traced resource. + $this") + } + return if (justHappened()) this.previousValue else this.value; + } + var traceEvent: Event? + get() { + if (!this.traced) { + throw BehaviorGraphException("Accessing traced event for non traced resource: $this"); + } else { + return if (this.justHappened()) this.previousEvent else this.event; + } + } + + init { + valuePersistence = ValuePersistence.Persistent + subsequents = HashSet() + traceValue = null + traceEvent = null + } + + @JvmOverloads + fun updateValue(newValue: T?, changesOnly: Boolean = false) { + if (this.graph == null) { + this.capturedUpdate = { this.updateValue(newValue, changesOnly) } + } else { + // Ensure valid graph structure + if (this.graph?.currentEvent == null) { + throw BehaviorGraphException("Added resources can only be updated during an event loop. Resource= $this") + } else { + if (this.suppliedBy != null && this.graph?.currentBehavior != this.suppliedBy) { + throw BehaviorGraphException("Resource can only be updated by its supplying behavior. Resource=$this currentBehavior= ${this.graph?.currentBehavior}"); + } + + if (changesOnly) { + if (this.value == newValue) { + return; + } + } + + if (this.traced) { + val previousSequence = this.previousEvent?.sequence ?: 0 + if (previousSequence < this.graph!!.currentEvent!!.sequence) { + this.previousValue = this.value; + this.previousEvent = this.event; + } else { + this.previousValue = null; + this.previousEvent = null; + } + } + + this.value = newValue; + this.event = this.graph!!.currentEvent; + this.graph!!.resourceTouched(this); + } + } + } + + fun justHappened(): Boolean { + val anEvent = this.event + val aCurrentEvent = this.graph?.currentEvent; + + return if (anEvent != null && aCurrentEvent != null) { + anEvent.sequence == aCurrentEvent.sequence; + } else { + false; + } + } + + fun hasHappened(): Boolean { + return this.event != null; + } + + fun happenedSince(since: Resource): Boolean { + val thisSequence = this.event?.sequence ?: -1; + val sinceSequence = since.event?.sequence ?: 0; + return thisSequence >= sinceSequence; + } + + fun happenedBetween(since: Resource, until: Resource): Boolean { + val thisSequence = this.event?.sequence ?: -1; + val sinceSequence = since.event?.sequence ?: 0; + val untilSequence = until.event?.sequence ?: Long.MAX_VALUE; + return thisSequence >= sinceSequence && thisSequence < untilSequence; + } + + override fun toString(): String { + return "Resource(value=$value, debugName=$debugName, valuePersistence=$valuePersistence, extent=$extent)" + } +} +*/ diff --git a/doc-site/examples/kotlin/BGExamples/com/yahoo/behaviorgraph/SideEffect.kt b/doc-site/examples/kotlin/BGExamples/com/yahoo/behaviorgraph/SideEffect.kt new file mode 100644 index 0000000..30019c1 --- /dev/null +++ b/doc-site/examples/kotlin/BGExamples/com/yahoo/behaviorgraph/SideEffect.kt @@ -0,0 +1,3 @@ +package com.yahoo.behaviorgraph + +data class SideEffect(val debugName: String?, val block: (extent: Extent<*>) -> Unit, val extent: Extent<*>) //todo contrain Extent more than "*"? diff --git a/doc-site/examples/kotlin/BGExamples/com/yahoo/behaviorgraph/State.kt b/doc-site/examples/kotlin/BGExamples/com/yahoo/behaviorgraph/State.kt new file mode 100644 index 0000000..6d2572a --- /dev/null +++ b/doc-site/examples/kotlin/BGExamples/com/yahoo/behaviorgraph/State.kt @@ -0,0 +1,69 @@ +package com.yahoo.behaviorgraph + +import com.yahoo.behaviorgraph.Event.Companion.InitialEvent + +class State(extent: Extent<*>, initialState: T, debugName: String? = null) : + Resource(extent, debugName), + Transient { + private var currentState = StateHistory(initialState, InitialEvent) + private var priorStateDuringEvent: StateHistory? = null + val value: T + get() = currentState.value + val event: Event + get() = currentState.event + private val trace: StateHistory + get() = priorStateDuringEvent ?: currentState + val traceValue: T + get() = trace.value + val traceEvent: Event + get() = trace.event + + fun updateWithAction(newValue: T, changesOnly: Boolean) { + graph.action(getImpulse()) { update(newValue, changesOnly) } + } + + fun update(newValue: T, changesOnly: Boolean) { + this.assertValidUpdater() + + if (changesOnly) { + if (newValue == currentState.value) + return + } + priorStateDuringEvent = currentState + currentState = StateHistory(newValue, this.graph.currentEvent!!) + this.graph.resourceTouched(this) + this.graph.trackTransient(this) + } + + private fun getImpulse(): String? { + return if (this.debugName != null) { + "Impulse From happen(): $this)" + } else null + } + + val justUpdated: Boolean + get() = currentState.event == graph.currentEvent + + fun justUpdatedTo(toValue: T): Boolean { + return justUpdated && + (currentState.value == toValue) + } + + fun justUpdatedFrom(fromValue: T): Boolean { + return justUpdated && + (priorStateDuringEvent!!.value == fromValue) + } + + fun justUpdatedToFrom(toValue: T, fromValue: T): Boolean { + return justUpdatedTo(toValue) && justUpdatedFrom(fromValue) + } + + override fun clear() { + priorStateDuringEvent = null + } + + data class StateHistory(val value: T, val event: Event) +} + + + diff --git a/doc-site/examples/kotlin/BGExamples/com/yahoo/behaviorgraph/Transient.kt b/doc-site/examples/kotlin/BGExamples/com/yahoo/behaviorgraph/Transient.kt new file mode 100644 index 0000000..50b2fbb --- /dev/null +++ b/doc-site/examples/kotlin/BGExamples/com/yahoo/behaviorgraph/Transient.kt @@ -0,0 +1,5 @@ +package com.yahoo.behaviorgraph + +interface Transient { + fun clear() : Unit +} diff --git a/doc-site/examples/kotlin/BGExamples/com/yahoo/behaviorgraph/ValuePersistence.kt b/doc-site/examples/kotlin/BGExamples/com/yahoo/behaviorgraph/ValuePersistence.kt new file mode 100644 index 0000000..845e5ad --- /dev/null +++ b/doc-site/examples/kotlin/BGExamples/com/yahoo/behaviorgraph/ValuePersistence.kt @@ -0,0 +1,7 @@ +package com.yahoo.behaviorgraph + +enum class ValuePersistence { + Persistent, + Transient, + TransientTrace +} diff --git a/doc-site/examples/kotlin/BGExamples/com/yahoo/behaviorgraph/exception/AllDemandsMustBeAddedToTheGraphExceptions.kt b/doc-site/examples/kotlin/BGExamples/com/yahoo/behaviorgraph/exception/AllDemandsMustBeAddedToTheGraphExceptions.kt new file mode 100644 index 0000000..371ad66 --- /dev/null +++ b/doc-site/examples/kotlin/BGExamples/com/yahoo/behaviorgraph/exception/AllDemandsMustBeAddedToTheGraphExceptions.kt @@ -0,0 +1,6 @@ +package com.yahoo.behaviorgraph.exception + +import com.yahoo.behaviorgraph.Behavior +import com.yahoo.behaviorgraph.Resource + +class AllDemandsMustBeAddedToTheGraphExceptions(s: String, val currentBehavior: Behavior, val untrackedDemand: Resource) : BehaviorGraphException("$s Behavior=$currentBehavior untrackedDemand=$untrackedDemand") diff --git a/doc-site/examples/kotlin/BGExamples/com/yahoo/behaviorgraph/exception/BehaviorDependencyCycleDetectedException.kt b/doc-site/examples/kotlin/BGExamples/com/yahoo/behaviorgraph/exception/BehaviorDependencyCycleDetectedException.kt new file mode 100644 index 0000000..7570204 --- /dev/null +++ b/doc-site/examples/kotlin/BGExamples/com/yahoo/behaviorgraph/exception/BehaviorDependencyCycleDetectedException.kt @@ -0,0 +1,7 @@ +package com.yahoo.behaviorgraph.exception + +import com.yahoo.behaviorgraph.Behavior +import com.yahoo.behaviorgraph.Resource + +class BehaviorDependencyCycleDetectedException(s: String, val behavior: Behavior, val cycle: List) : BehaviorGraphException("$s Behavior=$behavior") + diff --git a/doc-site/examples/kotlin/BGExamples/com/yahoo/behaviorgraph/exception/BehaviorGraphException.kt b/doc-site/examples/kotlin/BGExamples/com/yahoo/behaviorgraph/exception/BehaviorGraphException.kt new file mode 100644 index 0000000..50abd2c --- /dev/null +++ b/doc-site/examples/kotlin/BGExamples/com/yahoo/behaviorgraph/exception/BehaviorGraphException.kt @@ -0,0 +1,7 @@ +package com.yahoo.behaviorgraph.exception + +open class BehaviorGraphException : RuntimeException { + constructor(message: String, ex: Exception?): super(message, ex) + constructor(message: String): super(message) + constructor(ex: Exception): super(ex) +} diff --git a/doc-site/examples/kotlin/BGExamples/com/yahoo/behaviorgraph/exception/ExtentsCanOnlyBeAddedDuringAnEventException.kt b/doc-site/examples/kotlin/BGExamples/com/yahoo/behaviorgraph/exception/ExtentsCanOnlyBeAddedDuringAnEventException.kt new file mode 100644 index 0000000..5c00872 --- /dev/null +++ b/doc-site/examples/kotlin/BGExamples/com/yahoo/behaviorgraph/exception/ExtentsCanOnlyBeAddedDuringAnEventException.kt @@ -0,0 +1,6 @@ +package com.yahoo.behaviorgraph.exception + +import com.yahoo.behaviorgraph.Extent + +class ExtentsCanOnlyBeAddedDuringAnEventException(s: String, val extent: Extent<*>) : BehaviorGraphException("$s Extent=$extent") + diff --git a/doc-site/examples/kotlin/BGExamples/com/yahoo/behaviorgraph/exception/ExtentsCanOnlyBeRemovedDuringAnEventException.kt b/doc-site/examples/kotlin/BGExamples/com/yahoo/behaviorgraph/exception/ExtentsCanOnlyBeRemovedDuringAnEventException.kt new file mode 100644 index 0000000..4980f0f --- /dev/null +++ b/doc-site/examples/kotlin/BGExamples/com/yahoo/behaviorgraph/exception/ExtentsCanOnlyBeRemovedDuringAnEventException.kt @@ -0,0 +1,6 @@ +package com.yahoo.behaviorgraph.exception + +import com.yahoo.behaviorgraph.Extent + +class ExtentsCanOnlyBeRemovedDuringAnEventException(s: String, val extent: Extent<*>) : BehaviorGraphException("$s Extent=$extent") + diff --git a/doc-site/examples/kotlin/BGExamples/com/yahoo/behaviorgraph/exception/MissingInitialValuesException.kt b/doc-site/examples/kotlin/BGExamples/com/yahoo/behaviorgraph/exception/MissingInitialValuesException.kt new file mode 100644 index 0000000..c393287 --- /dev/null +++ b/doc-site/examples/kotlin/BGExamples/com/yahoo/behaviorgraph/exception/MissingInitialValuesException.kt @@ -0,0 +1,5 @@ +package com.yahoo.behaviorgraph.exception + +import com.yahoo.behaviorgraph.Resource + +class MissingInitialValuesException(s: String, val resource: Resource) : BehaviorGraphException("$s Resource=$resource") diff --git a/doc-site/examples/kotlin/BGExamples/com/yahoo/behaviorgraph/exception/ResourceCannotBeSuppliedByMoreThanOneBehaviorException.kt b/doc-site/examples/kotlin/BGExamples/com/yahoo/behaviorgraph/exception/ResourceCannotBeSuppliedByMoreThanOneBehaviorException.kt new file mode 100644 index 0000000..9c062a9 --- /dev/null +++ b/doc-site/examples/kotlin/BGExamples/com/yahoo/behaviorgraph/exception/ResourceCannotBeSuppliedByMoreThanOneBehaviorException.kt @@ -0,0 +1,6 @@ +package com.yahoo.behaviorgraph.exception + +import com.yahoo.behaviorgraph.Behavior +import com.yahoo.behaviorgraph.Resource + +class ResourceCannotBeSuppliedByMoreThanOneBehaviorException(s: String, val alreadySupplied: Resource, val desiredSupplier: Behavior) : BehaviorGraphException("$s alreadySupplied=$alreadySupplied desiredSupplier=$desiredSupplier") diff --git a/doc-site/examples/kotlin/BGExamples/com/yahoo/behaviorgraph/platform/PlatformSupport.kt b/doc-site/examples/kotlin/BGExamples/com/yahoo/behaviorgraph/platform/PlatformSupport.kt new file mode 100644 index 0000000..39c3492 --- /dev/null +++ b/doc-site/examples/kotlin/BGExamples/com/yahoo/behaviorgraph/platform/PlatformSupport.kt @@ -0,0 +1,11 @@ +package com.yahoo.behaviorgraph.platform + +interface PlatformSupport { + fun isMainThread(): Boolean + fun getCurrentTimeMillis(): Long + fun now() = getCurrentTimeMillis() + + companion object { + lateinit var platformSupport: PlatformSupport + } +} diff --git a/doc-site/examples/kotlin/kotlin.iml b/doc-site/examples/kotlin/kotlin.iml new file mode 100644 index 0000000..7b6c2b0 --- /dev/null +++ b/doc-site/examples/kotlin/kotlin.iml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/doc-site/examples/objc/.gitignore b/doc-site/examples/objc/.gitignore new file mode 100644 index 0000000..8ee1ded --- /dev/null +++ b/doc-site/examples/objc/.gitignore @@ -0,0 +1 @@ +**/xcuserdata diff --git a/doc-site/examples/objc/BGExamples.xcodeproj/project.pbxproj b/doc-site/examples/objc/BGExamples.xcodeproj/project.pbxproj new file mode 100644 index 0000000..d433fd9 --- /dev/null +++ b/doc-site/examples/objc/BGExamples.xcodeproj/project.pbxproj @@ -0,0 +1,545 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 50; + objects = { + +/* Begin PBXBuildFile section */ + 7301269A2422C0810031659C /* LoginPageViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 730126992422C0810031659C /* LoginPageViewController.m */; }; + 7301269D2422C2780031659C /* ImperativeLoginPageViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 7301269C2422C2780031659C /* ImperativeLoginPageViewController.m */; }; + 730126A02422E2900031659C /* LoginExtent.m in Sources */ = {isa = PBXBuildFile; fileRef = 7301269F2422E2900031659C /* LoginExtent.m */; }; + 73265A3825A13B8700B0BF84 /* BGPriorityQueue.m in Sources */ = {isa = PBXBuildFile; fileRef = 73265A3625A13B8700B0BF84 /* BGPriorityQueue.m */; }; + 73C56CB7241293A300066BC4 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 73C56CB6241293A300066BC4 /* AppDelegate.m */; }; + 73C56CBA241293A300066BC4 /* SceneDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 73C56CB9241293A300066BC4 /* SceneDelegate.m */; }; + 73C56CBD241293A300066BC4 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 73C56CBC241293A300066BC4 /* ViewController.m */; }; + 73C56CC0241293A300066BC4 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 73C56CBE241293A300066BC4 /* Main.storyboard */; }; + 73C56CC2241293A500066BC4 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 73C56CC1241293A500066BC4 /* Assets.xcassets */; }; + 73C56CC5241293A500066BC4 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 73C56CC3241293A500066BC4 /* LaunchScreen.storyboard */; }; + 73C56CC8241293A500066BC4 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 73C56CC7241293A500066BC4 /* main.m */; }; + 73C56CD2241293A600066BC4 /* BGExamplesTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 73C56CD1241293A600066BC4 /* BGExamplesTests.m */; }; + 73C56CEC241296F000066BC4 /* BGProfiler.m in Sources */ = {isa = PBXBuildFile; fileRef = 73C56CE7241296EF00066BC4 /* BGProfiler.m */; }; + 73C56CED241296F000066BC4 /* BGGraph.m in Sources */ = {isa = PBXBuildFile; fileRef = 73C56CEB241296F000066BC4 /* BGGraph.m */; }; + 73C56CF42412981700066BC4 /* SigngupPageViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 73C56CF22412981700066BC4 /* SigngupPageViewController.m */; }; + 73C56CF8241298A600066BC4 /* SignupExtent.m in Sources */ = {isa = PBXBuildFile; fileRef = 73C56CF7241298A600066BC4 /* SignupExtent.m */; }; + 73F5F5D5246C5F12006236D8 /* ChatExtent.m in Sources */ = {isa = PBXBuildFile; fileRef = 73F5F5D4246C5F12006236D8 /* ChatExtent.m */; }; + 73F5F5D8246C5F56006236D8 /* ParticipantExtent.m in Sources */ = {isa = PBXBuildFile; fileRef = 73F5F5D7246C5F56006236D8 /* ParticipantExtent.m */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 73C56CCE241293A600066BC4 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 73C56CAA241293A300066BC4 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 73C56CB1241293A300066BC4; + remoteInfo = BGExamples; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXFileReference section */ + 730126982422C0810031659C /* LoginPageViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LoginPageViewController.h; sourceTree = ""; }; + 730126992422C0810031659C /* LoginPageViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = LoginPageViewController.m; sourceTree = ""; }; + 7301269B2422C2780031659C /* ImperativeLoginPageViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ImperativeLoginPageViewController.h; sourceTree = ""; }; + 7301269C2422C2780031659C /* ImperativeLoginPageViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ImperativeLoginPageViewController.m; sourceTree = ""; }; + 7301269E2422E2900031659C /* LoginExtent.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LoginExtent.h; sourceTree = ""; }; + 7301269F2422E2900031659C /* LoginExtent.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = LoginExtent.m; sourceTree = ""; }; + 73265A3625A13B8700B0BF84 /* BGPriorityQueue.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BGPriorityQueue.m; sourceTree = ""; }; + 73265A3725A13B8700B0BF84 /* BGPriorityQueue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BGPriorityQueue.h; sourceTree = ""; }; + 73C56CB2241293A300066BC4 /* BGExamples.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = BGExamples.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 73C56CB5241293A300066BC4 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; + 73C56CB6241293A300066BC4 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; + 73C56CB8241293A300066BC4 /* SceneDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SceneDelegate.h; sourceTree = ""; }; + 73C56CB9241293A300066BC4 /* SceneDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SceneDelegate.m; sourceTree = ""; }; + 73C56CBB241293A300066BC4 /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; + 73C56CBC241293A300066BC4 /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; + 73C56CBF241293A300066BC4 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 73C56CC1241293A500066BC4 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 73C56CC4241293A500066BC4 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + 73C56CC6241293A500066BC4 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 73C56CC7241293A500066BC4 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; + 73C56CCD241293A600066BC4 /* BGExamplesTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = BGExamplesTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 73C56CD1241293A600066BC4 /* BGExamplesTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = BGExamplesTests.m; sourceTree = ""; }; + 73C56CD3241293A600066BC4 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 73C56CE7241296EF00066BC4 /* BGProfiler.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BGProfiler.m; sourceTree = ""; }; + 73C56CE8241296EF00066BC4 /* BGGraph.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BGGraph.h; sourceTree = ""; }; + 73C56CE9241296EF00066BC4 /* BGGraph+Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "BGGraph+Private.h"; sourceTree = ""; }; + 73C56CEA241296EF00066BC4 /* BGProfiler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BGProfiler.h; sourceTree = ""; }; + 73C56CEB241296F000066BC4 /* BGGraph.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BGGraph.m; sourceTree = ""; }; + 73C56CF12412981700066BC4 /* SigngupPageViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SigngupPageViewController.h; sourceTree = ""; }; + 73C56CF22412981700066BC4 /* SigngupPageViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SigngupPageViewController.m; sourceTree = ""; }; + 73C56CF6241298A600066BC4 /* SignupExtent.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SignupExtent.h; sourceTree = ""; }; + 73C56CF7241298A600066BC4 /* SignupExtent.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SignupExtent.m; sourceTree = ""; }; + 73F5F5D3246C5F12006236D8 /* ChatExtent.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ChatExtent.h; sourceTree = ""; }; + 73F5F5D4246C5F12006236D8 /* ChatExtent.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ChatExtent.m; sourceTree = ""; }; + 73F5F5D6246C5F56006236D8 /* ParticipantExtent.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ParticipantExtent.h; sourceTree = ""; }; + 73F5F5D7246C5F56006236D8 /* ParticipantExtent.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ParticipantExtent.m; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 73C56CAF241293A300066BC4 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 73C56CCA241293A600066BC4 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 73C56CA9241293A300066BC4 = { + isa = PBXGroup; + children = ( + 73C56CB4241293A300066BC4 /* BGExamples */, + 73C56CD0241293A600066BC4 /* BGExamplesTests */, + 73C56CB3241293A300066BC4 /* Products */, + ); + sourceTree = ""; + }; + 73C56CB3241293A300066BC4 /* Products */ = { + isa = PBXGroup; + children = ( + 73C56CB2241293A300066BC4 /* BGExamples.app */, + 73C56CCD241293A600066BC4 /* BGExamplesTests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + 73C56CB4241293A300066BC4 /* BGExamples */ = { + isa = PBXGroup; + children = ( + 73C56CDC241293BD00066BC4 /* BehaviorGraph */, + 73C56CB5241293A300066BC4 /* AppDelegate.h */, + 73C56CB6241293A300066BC4 /* AppDelegate.m */, + 73C56CF12412981700066BC4 /* SigngupPageViewController.h */, + 73C56CF22412981700066BC4 /* SigngupPageViewController.m */, + 730126982422C0810031659C /* LoginPageViewController.h */, + 730126992422C0810031659C /* LoginPageViewController.m */, + 7301269B2422C2780031659C /* ImperativeLoginPageViewController.h */, + 7301269C2422C2780031659C /* ImperativeLoginPageViewController.m */, + 73C56CF6241298A600066BC4 /* SignupExtent.h */, + 73C56CF7241298A600066BC4 /* SignupExtent.m */, + 7301269E2422E2900031659C /* LoginExtent.h */, + 7301269F2422E2900031659C /* LoginExtent.m */, + 73C56CB8241293A300066BC4 /* SceneDelegate.h */, + 73C56CB9241293A300066BC4 /* SceneDelegate.m */, + 73C56CBB241293A300066BC4 /* ViewController.h */, + 73C56CBC241293A300066BC4 /* ViewController.m */, + 73F5F5D3246C5F12006236D8 /* ChatExtent.h */, + 73F5F5D4246C5F12006236D8 /* ChatExtent.m */, + 73F5F5D6246C5F56006236D8 /* ParticipantExtent.h */, + 73F5F5D7246C5F56006236D8 /* ParticipantExtent.m */, + 73C56CBE241293A300066BC4 /* Main.storyboard */, + 73C56CC1241293A500066BC4 /* Assets.xcassets */, + 73C56CC3241293A500066BC4 /* LaunchScreen.storyboard */, + 73C56CC6241293A500066BC4 /* Info.plist */, + 73C56CC7241293A500066BC4 /* main.m */, + ); + path = BGExamples; + sourceTree = ""; + }; + 73C56CD0241293A600066BC4 /* BGExamplesTests */ = { + isa = PBXGroup; + children = ( + 73C56CD1241293A600066BC4 /* BGExamplesTests.m */, + 73C56CD3241293A600066BC4 /* Info.plist */, + ); + path = BGExamplesTests; + sourceTree = ""; + }; + 73C56CDC241293BD00066BC4 /* BehaviorGraph */ = { + isa = PBXGroup; + children = ( + 73C56CE8241296EF00066BC4 /* BGGraph.h */, + 73C56CEB241296F000066BC4 /* BGGraph.m */, + 73C56CE9241296EF00066BC4 /* BGGraph+Private.h */, + 73C56CEA241296EF00066BC4 /* BGProfiler.h */, + 73C56CE7241296EF00066BC4 /* BGProfiler.m */, + 73265A3725A13B8700B0BF84 /* BGPriorityQueue.h */, + 73265A3625A13B8700B0BF84 /* BGPriorityQueue.m */, + ); + path = BehaviorGraph; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 73C56CB1241293A300066BC4 /* BGExamples */ = { + isa = PBXNativeTarget; + buildConfigurationList = 73C56CD6241293A600066BC4 /* Build configuration list for PBXNativeTarget "BGExamples" */; + buildPhases = ( + 73C56CAE241293A300066BC4 /* Sources */, + 73C56CAF241293A300066BC4 /* Frameworks */, + 73C56CB0241293A300066BC4 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = BGExamples; + productName = BGExamples; + productReference = 73C56CB2241293A300066BC4 /* BGExamples.app */; + productType = "com.apple.product-type.application"; + }; + 73C56CCC241293A600066BC4 /* BGExamplesTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 73C56CD9241293A600066BC4 /* Build configuration list for PBXNativeTarget "BGExamplesTests" */; + buildPhases = ( + 73C56CC9241293A600066BC4 /* Sources */, + 73C56CCA241293A600066BC4 /* Frameworks */, + 73C56CCB241293A600066BC4 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 73C56CCF241293A600066BC4 /* PBXTargetDependency */, + ); + name = BGExamplesTests; + productName = BGExamplesTests; + productReference = 73C56CCD241293A600066BC4 /* BGExamplesTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 73C56CAA241293A300066BC4 /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 1230; + ORGANIZATIONNAME = "Verizon Media"; + TargetAttributes = { + 73C56CB1241293A300066BC4 = { + CreatedOnToolsVersion = 11.3; + }; + 73C56CCC241293A600066BC4 = { + CreatedOnToolsVersion = 11.3; + TestTargetID = 73C56CB1241293A300066BC4; + }; + }; + }; + buildConfigurationList = 73C56CAD241293A300066BC4 /* Build configuration list for PBXProject "BGExamples" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 73C56CA9241293A300066BC4; + productRefGroup = 73C56CB3241293A300066BC4 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 73C56CB1241293A300066BC4 /* BGExamples */, + 73C56CCC241293A600066BC4 /* BGExamplesTests */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 73C56CB0241293A300066BC4 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 73C56CC5241293A500066BC4 /* LaunchScreen.storyboard in Resources */, + 73C56CC2241293A500066BC4 /* Assets.xcassets in Resources */, + 73C56CC0241293A300066BC4 /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 73C56CCB241293A600066BC4 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 73C56CAE241293A300066BC4 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 73C56CBD241293A300066BC4 /* ViewController.m in Sources */, + 73C56CB7241293A300066BC4 /* AppDelegate.m in Sources */, + 73C56CC8241293A500066BC4 /* main.m in Sources */, + 73C56CEC241296F000066BC4 /* BGProfiler.m in Sources */, + 73C56CBA241293A300066BC4 /* SceneDelegate.m in Sources */, + 73F5F5D8246C5F56006236D8 /* ParticipantExtent.m in Sources */, + 730126A02422E2900031659C /* LoginExtent.m in Sources */, + 73265A3825A13B8700B0BF84 /* BGPriorityQueue.m in Sources */, + 73C56CF8241298A600066BC4 /* SignupExtent.m in Sources */, + 7301269A2422C0810031659C /* LoginPageViewController.m in Sources */, + 7301269D2422C2780031659C /* ImperativeLoginPageViewController.m in Sources */, + 73C56CED241296F000066BC4 /* BGGraph.m in Sources */, + 73C56CF42412981700066BC4 /* SigngupPageViewController.m in Sources */, + 73F5F5D5246C5F12006236D8 /* ChatExtent.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 73C56CC9241293A600066BC4 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 73C56CD2241293A600066BC4 /* BGExamplesTests.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 73C56CCF241293A600066BC4 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 73C56CB1241293A300066BC4 /* BGExamples */; + targetProxy = 73C56CCE241293A600066BC4 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin PBXVariantGroup section */ + 73C56CBE241293A300066BC4 /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 73C56CBF241293A300066BC4 /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 73C56CC3241293A500066BC4 /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 73C56CC4241293A500066BC4 /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 73C56CD4241293A600066BC4 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 13.2; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + }; + name = Debug; + }; + 73C56CD5241293A600066BC4 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 13.2; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + SDKROOT = iphoneos; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 73C56CD7241293A600066BC4 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = ""; + INFOPLIST_FILE = BGExamples/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 12.1; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.yahoo.BGExamples; + PRODUCT_NAME = "$(TARGET_NAME)"; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 73C56CD8241293A600066BC4 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = ""; + INFOPLIST_FILE = BGExamples/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 12.1; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.yahoo.BGExamples; + PRODUCT_NAME = "$(TARGET_NAME)"; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; + 73C56CDA241293A600066BC4 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + INFOPLIST_FILE = BGExamplesTests/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 13.2; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.yahoo.BGExamplesTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + TARGETED_DEVICE_FAMILY = "1,2"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/BGExamples.app/BGExamples"; + }; + name = Debug; + }; + 73C56CDB241293A600066BC4 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + INFOPLIST_FILE = BGExamplesTests/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 13.2; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.yahoo.BGExamplesTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + TARGETED_DEVICE_FAMILY = "1,2"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/BGExamples.app/BGExamples"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 73C56CAD241293A300066BC4 /* Build configuration list for PBXProject "BGExamples" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 73C56CD4241293A600066BC4 /* Debug */, + 73C56CD5241293A600066BC4 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 73C56CD6241293A600066BC4 /* Build configuration list for PBXNativeTarget "BGExamples" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 73C56CD7241293A600066BC4 /* Debug */, + 73C56CD8241293A600066BC4 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 73C56CD9241293A600066BC4 /* Build configuration list for PBXNativeTarget "BGExamplesTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 73C56CDA241293A600066BC4 /* Debug */, + 73C56CDB241293A600066BC4 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 73C56CAA241293A300066BC4 /* Project object */; +} diff --git a/doc-site/examples/objc/BGExamples.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/doc-site/examples/objc/BGExamples.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..5fe0322 --- /dev/null +++ b/doc-site/examples/objc/BGExamples.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/doc-site/examples/objc/BGExamples.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/doc-site/examples/objc/BGExamples.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/doc-site/examples/objc/BGExamples.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/doc-site/examples/objc/BGExamples.xcworkspace/contents.xcworkspacedata b/doc-site/examples/objc/BGExamples.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..4ccb116 --- /dev/null +++ b/doc-site/examples/objc/BGExamples.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/doc-site/examples/objc/BGExamples.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/doc-site/examples/objc/BGExamples.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/doc-site/examples/objc/BGExamples.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/doc-site/examples/objc/BGExamples/AppDelegate.h b/doc-site/examples/objc/BGExamples/AppDelegate.h new file mode 100644 index 0000000..ca9673c --- /dev/null +++ b/doc-site/examples/objc/BGExamples/AppDelegate.h @@ -0,0 +1,15 @@ +// +// AppDelegate.h +// BGExamples +// +// Created by Sean Levin on 3/6/20. +// Copyright © 2020 Verizon Media. All rights reserved. +// + +#import + +@interface AppDelegate : UIResponder + + +@end + diff --git a/doc-site/examples/objc/BGExamples/AppDelegate.m b/doc-site/examples/objc/BGExamples/AppDelegate.m new file mode 100644 index 0000000..7d1d3f7 --- /dev/null +++ b/doc-site/examples/objc/BGExamples/AppDelegate.m @@ -0,0 +1,41 @@ +// +// AppDelegate.m +// BGExamples +// +// Created by Sean Levin on 3/6/20. +// Copyright © 2020 Verizon Media. All rights reserved. +// + +#import "AppDelegate.h" + +@interface AppDelegate () + +@end + +@implementation AppDelegate + + +- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { + // Override point for customization after application launch. + return YES; +} + + +#pragma mark - UISceneSession lifecycle + + +- (UISceneConfiguration *)application:(UIApplication *)application configurationForConnectingSceneSession:(UISceneSession *)connectingSceneSession options:(UISceneConnectionOptions *)options { + // Called when a new scene session is being created. + // Use this method to select a configuration to create the new scene with. + return [[UISceneConfiguration alloc] initWithName:@"Default Configuration" sessionRole:connectingSceneSession.role]; +} + + +- (void)application:(UIApplication *)application didDiscardSceneSessions:(NSSet *)sceneSessions { + // Called when the user discards a scene session. + // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions. + // Use this method to release any resources that were specific to the discarded scenes, as they will not return. +} + + +@end diff --git a/doc-site/examples/objc/BGExamples/Assets.xcassets/AppIcon.appiconset/Contents.json b/doc-site/examples/objc/BGExamples/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..d8db8d6 --- /dev/null +++ b/doc-site/examples/objc/BGExamples/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,98 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "size" : "20x20", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "20x20", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "3x" + }, + { + "idiom" : "ipad", + "size" : "20x20", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "20x20", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "76x76", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "76x76", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "83.5x83.5", + "scale" : "2x" + }, + { + "idiom" : "ios-marketing", + "size" : "1024x1024", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/doc-site/examples/objc/BGExamples/Assets.xcassets/Contents.json b/doc-site/examples/objc/BGExamples/Assets.xcassets/Contents.json new file mode 100644 index 0000000..da4a164 --- /dev/null +++ b/doc-site/examples/objc/BGExamples/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/doc-site/examples/objc/BGExamples/Base.lproj/LaunchScreen.storyboard b/doc-site/examples/objc/BGExamples/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 0000000..f2b70d1 --- /dev/null +++ b/doc-site/examples/objc/BGExamples/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc-site/examples/objc/BGExamples/Base.lproj/Main.storyboard b/doc-site/examples/objc/BGExamples/Base.lproj/Main.storyboard new file mode 100644 index 0000000..e8a10d1 --- /dev/null +++ b/doc-site/examples/objc/BGExamples/Base.lproj/Main.storyboard @@ -0,0 +1,121 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc-site/examples/objc/BGExamples/BehaviorGraph/BGGraph+Private.h b/doc-site/examples/objc/BGExamples/BehaviorGraph/BGGraph+Private.h new file mode 100644 index 0000000..d294ff5 --- /dev/null +++ b/doc-site/examples/objc/BGExamples/BehaviorGraph/BGGraph+Private.h @@ -0,0 +1,144 @@ +// +// BGGraph+Private.h +// YVideoSDK +// +// Created by James Lou on 4/11/19. +// Copyright © 2019 Yahoo. All rights reserved. +// + +#import "BGGraph.h" +#import "BGPriorityQueue.h" +#import + +static NSObject * _Nonnull NullPushedValue; + +typedef NS_ENUM(NSInteger, BGOrderingState) { + BGOrderingStateUnordered, + BGOrderingStateOrdering, + BGOrderingStateOrdered, +}; + +typedef NS_ENUM(NSInteger, BGResourceValuePersistence) { + BGResourcePersistent, + BGResourceTransient, + BGResourceTransientTrace, +}; + + +@interface BGEvent () +- (instancetype _Nonnull)initWithImpulse:(NSString * _Nullable )impulse sequence:(NSUInteger)sequence timestamp:(NSDate * _Nonnull)timestamp; +@end + +@interface BGResource<__covariant ValueType> () { + @protected + __weak BGGraph *_graph; + __weak BGExtent *_extent; + __weak BGBehavior *_behavior; + NSHashTable *_subsequents; + BGEvent *_added; + NSString *_staticDebugName; +} +@property (nonatomic, readwrite, weak, nullable) BGGraph *graph; +@property (nonatomic, readwrite, weak, nullable) BGExtent *extent; +@property (nonatomic, readwrite, weak, nullable) BGBehavior *behavior; +@property (nonatomic, readwrite, nullable) BGEvent *added; +@property (nonatomic, readonly, nonnull) NSHashTable *subsequents; +@property (nonatomic, nullable) void (^capturedInitialUpdate)(void); +@property (nonatomic, readonly) BOOL traced; +@property (nonatomic, readonly) BGResourceValuePersistence valuePersistence; +@property (nonatomic, nullable) ValueType previousValue; +@property (nonatomic, nullable) BGEvent *previousEvent; +- (instancetype _Nonnull)initWithExtent:(BGExtent * _Nonnull)extent value:(ValueType _Nullable)value event:(BGEvent * _Nullable)event; +- (void)_updateValue:(ValueType _Nullable)value; +- (void)_forceUpdateValue:(ValueType _Nullable)value; +- (void)clearTransient; +@end + + +@interface BGMoment<__covariant ValueType> () +@end + +@interface BGState<__covariant ValueType> () +@end + +@interface BGBehavior () +@property (nonatomic, readonly, nonnull) NSHashTable *supplies; +@property (nonatomic, readwrite, nullable) BGGraph *graph; +@property (nonatomic, readwrite, weak, nullable) BGExtent *extent; +@property (nonatomic, nullable) NSMutableArray *modifiedDemands; +@property (nonatomic, readonly, nullable) NSHashTable *demands; +@property (nonatomic) NSUInteger removedSequence; +@property (nonatomic) NSUInteger lastUpdateSequence; +@property (nonatomic) NSUInteger order; +@property (nonatomic) BGOrderingState orderingState; +@property (nonatomic) NSUInteger enqueuedSequence; +@end + +@interface BGAction : NSObject +@property (nonatomic, nullable) NSString *name; +@property (nonatomic, nonnull) dispatch_block_t block; +- (instancetype _Nonnull)initWithName:(NSString * _Nullable)name block:(dispatch_block_t _Nonnull)block; +@end + +@interface BGSideEffect : NSObject { +@protected + NSString * _Nullable _name; + BGEvent * _Nonnull _event; +} +@property (nonatomic, readonly, nullable) NSString *name; +@property (nonatomic, readonly, nonnull) BGEvent *event; +- (void)run; +@end + +@interface BGBehaviorSideEffect : BGSideEffect +@property (nonatomic, readonly, nonnull) BGExtent *extent; +@property (nonatomic, readonly, nonnull) void(^block)(BGExtent * _Nonnull extent); +- (instancetype _Nonnull)initWithName:(NSString * _Nullable)name event:(BGEvent * _Nonnull)event extent:(BGExtent * _Nonnull)extent block:(void(^ _Nonnull)(BGExtent * _Nullable))block; +@end + +@interface BGGraphSideEffect : BGSideEffect +@property (nonatomic, readonly, nonnull) dispatch_block_t block; +- (instancetype _Nonnull)initWithName:(NSString * _Nullable)name event:(BGEvent * _Nonnull)event block:(dispatch_block_t _Nonnull)block; +@end + +@interface BGEventLoopState : NSObject +@property (nonatomic, nonnull) BGEvent *event; +@property (nonatomic, readonly) NSUInteger sequence; +@property (nonatomic) unsigned long long eventSid; +@property (nonatomic) BOOL processingAction; +@property (nonatomic) BOOL processingChanges; +@end + +@interface BGGraph () +@property (nonatomic, nullable) BGEventLoopState *eventLoopState; +@property (nonatomic, readonly) NSUInteger sequence; +@property (nonatomic, readonly) BOOL processingAction; +@property (nonatomic, readonly) BOOL processingChanges; +@property (nonatomic) NSUInteger eventLoopDrivers; +@property (nonatomic, nonnull) NSMutableSet *needsOrdering; +@property (nonatomic, readonly, nonnull) NSMutableArray *afterChanges; +@property (nonatomic, readonly, nonnull) NSMutableSet *untrackedBehaviors; +@property (nonatomic, readonly, nonnull) NSMutableSet *modifiedDemands; +@property (nonatomic, readonly, nonnull) NSMutableArray *updatedTransientResources; +@property (nonatomic, readonly, nonnull) NSMutableArray *deferredRelease; +@property (nonatomic, readonly, nonnull) BGPriorityQueue *behaviorQueue; +@property (nonatomic, readonly, nullable) BGBehavior * currentBehavior; +@property (nonatomic, readonly, nullable) os_log_t aclog; +@property (nonatomic, readonly, nullable) os_log_t splog; + +@property (nonatomic, readonly, nullable) NSMutableArray *actionQueue; +@property (nonatomic, readonly, nullable) NSMutableArray *sideEffectQueue; + +- (void)submitToQueue:(BGBehavior * _Nonnull)subsequent; +- (void)removeBehavior:(BGBehavior * _Nonnull)behavior; +- (void)trackTransient:(BGResource * _Nonnull)rez; +@end + +@interface BGExtent () +@property (nonatomic, nullable) BGEvent *addedToGraph; +@property (nonatomic, readonly, nullable) NSMutableSet *allBehaviors; +@property (nonatomic, readonly, nullable) NSMutableSet *allResources; +- (void)addBehavior:(BGBehavior * _Nonnull)behavior; +- (void)addResource:(BGResource * _Nonnull)resource; +- (void)nameComponents; +@end diff --git a/doc-site/examples/objc/BGExamples/BehaviorGraph/BGGraph.h b/doc-site/examples/objc/BGExamples/BehaviorGraph/BGGraph.h new file mode 100644 index 0000000..7d8444b --- /dev/null +++ b/doc-site/examples/objc/BGExamples/BehaviorGraph/BGGraph.h @@ -0,0 +1,117 @@ +// +// BGGraph.h +// YVideoSDK +// +// Created by James Lou on 2/7/19. +// Copyright © 2019 Yahoo. All rights reserved. +// + +#import + +#define _fname ([NSString stringWithFormat:@"%@.%@", NSStringFromClass(self.class), NSStringFromSelector(_cmd)]) + +@class BGBehavior; +@class BGGraph; + +@class BGExtent; + +@interface BGEvent : NSObject +@property (nonatomic, readonly) NSUInteger sequence; +@property (nonatomic, readonly, nonnull) NSDate *timestamp; +@property (nonatomic, readonly, nullable) NSString *impulse; +@property (nonatomic, readonly, class, nonnull) BGEvent *unknownPast; +- (BOOL)happenedSince:(NSUInteger)since; +@end + + +@interface BGResource<__covariant ValueType> : NSObject +@property (nonatomic, readonly, weak, nullable) BGGraph *graph; +@property (nonatomic, readonly, weak, nullable) BGExtent *extent; +@property (nonatomic, readonly, weak, nullable) BGBehavior *behavior; +@property (nonatomic, readonly, nullable) BGEvent *added; +@property (nonatomic, nullable) NSString *staticDebugName; + +@property (nonatomic, readonly, nullable) ValueType value; +@property (nonatomic, readonly, nullable) ValueType traceValue; +@property (nonatomic, readonly, nonnull) BGEvent *event; +@property (nonatomic, readonly, nonnull) BGEvent *traceEvent; + +@property (nonatomic, readonly) BOOL justAdded; +@property (nonatomic, readonly) BOOL justUpdated; +@property (nonatomic, readonly) BOOL hasUpdated; +@property (nonatomic, readonly) BOOL traceHasUpdated; +- (BOOL)hasUpdatedSince:(BGResource * _Nonnull)since; +- (instancetype _Nonnull)initWithExtent:(BGExtent * _Nonnull)extent; +- (instancetype _Nonnull)init NS_UNAVAILABLE; ++ (instancetype _Nonnull)new NS_UNAVAILABLE; +- (BOOL)justUpdatedTo:(ValueType _Nullable)toValue; +@end + +@interface BGMoment<__covariant ValueType> : BGResource +- (void)update; +- (void)updateValue:(ValueType _Nullable)value; +@end + +@interface BGState<__covariant ValueType> : BGResource +- (instancetype _Nonnull)initWithExtent:(BGExtent * _Nonnull)extent value:(ValueType _Nullable)value NS_DESIGNATED_INITIALIZER; +- (void)updateValue:(ValueType _Nullable)value; +- (void)updateValueForce:(ValueType _Nullable)value; +- (BOOL)justUpdatedFrom:(ValueType _Nullable)fromValue; +- (BOOL)justUpdatedTo:(ValueType _Nullable)toValue from:(ValueType _Nullable)fromValue; +@end + +@interface BGBehavior : NSObject +@property (nonatomic, nullable) void(^runBlock)(BGExtent * _Nonnull extent); +@property (nonatomic, nullable) NSString *staticDebugName; +@property (nonatomic, readonly, weak, nullable) BGGraph *graph; +@property (nonatomic, readonly, weak, nullable) BGExtent *extent; +- (instancetype _Nonnull)initWithExtent:(BGExtent * _Nonnull)extent + demands:(NSArray * _Nullable)demands + supplies:(NSArray * _Nullable)supplies + runBlock:(void(^_Nullable)(BGExtent * _Nonnull extent))runBlock; +- (void)setDemands:(NSArray * _Nullable)demands; +- (void)addDemand:(BGResource * _Nonnull)demand; +- (void)removeDemand:(BGResource * _Nonnull)demand; + +- (void)setSupplies:(NSArray * _Nullable)supplies; +@end + +@protocol BGDateProvider +- (NSDate * _Nonnull)bg_currentDate; +@end + +@interface BGGraph : NSObject +@property (nonatomic, readonly, nonnull) BGBehavior *mainNode; +@property (nonatomic, readonly, nullable) BGEvent *currentEvent; +@property (nonatomic, readonly, nullable) BGEvent *lastEvent; +@property (nonatomic, readonly, nonnull) BGState *currentEventResource; +@property (nonatomic, weak, nullable) id dateProvider; +@property (nonatomic, readonly, nonnull) BGExtent *rootExtent; +@property (nonatomic) BOOL defaultRequireSync; +@property (nonatomic) BOOL assertOnLeakedSideEffects; + +- (void)action:(NSString * _Nullable)impulse runBlock:(dispatch_block_t _Nonnull)changes; +- (void)action:(NSString * _Nullable)impulse requireSync:(BOOL)requireSync runBlock:(dispatch_block_t _Nonnull)changes; +- (void)sideEffect:(NSString * _Nullable)name runBlock:(dispatch_block_t _Nonnull)block; +@end + +@interface BGExtent<__covariant SubType> : NSObject +@property (nonatomic, readonly, weak, nullable) BGGraph *graph; +@property (nonatomic, readonly, nullable) NSString *debugHere; + +- (instancetype _Nonnull)initWithGraph:(BGGraph * _Nonnull)graph NS_DESIGNATED_INITIALIZER; +- (instancetype _Nonnull)init NS_UNAVAILABLE; ++ (instancetype _Nonnull)new NS_UNAVAILABLE; +- (void)addToGraph; +- (void)removeFromGraph; +- (BGBehavior * _Nonnull)behaviorWithDemands:(NSArray * _Nullable)demands + supplies:(NSArray * _Nullable)supplies + runBlock:(void(^_Nullable)(SubType _Nonnull extent))runBlock; + +- (void)sideEffect:(NSString * _Nullable)name runBlock:(void(^ _Nonnull)(SubType _Nonnull extent))block; +- (BGMoment * _Nonnull)moment; +- (BGResource * _Nonnull)resource; +- (BGState * _Nonnull)stateWithValue:(id _Nullable)value; +@end + + diff --git a/doc-site/examples/objc/BGExamples/BehaviorGraph/BGGraph.m b/doc-site/examples/objc/BGExamples/BehaviorGraph/BGGraph.m new file mode 100644 index 0000000..f7cdbc4 --- /dev/null +++ b/doc-site/examples/objc/BGExamples/BehaviorGraph/BGGraph.m @@ -0,0 +1,1157 @@ +// +// BGGraph.m +// YVideoSDK +// +// Created by James Lou on 2/7/19. +// Copyright © 2019 Yahoo. All rights reserved. +// + +#import "BGGraph+Private.h" + +#import + +#define PriorlessOrder 0 + + +BOOL bg_equal(NSObject *obj1, NSObject *obj2) { + return (obj1 && obj2 && [obj1 isEqual:obj2]) || (!obj1 && !obj2); +} + +static BGEvent* BGUnknownPast; + +@implementation BGEvent + ++ (void)initialize { + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + if (self == BGEvent.class) { + BGUnknownPast = [[BGEvent alloc] initWithImpulse:@"UnknownPast" sequence:0 timestamp:[NSDate dateWithTimeIntervalSince1970:0]]; + } + }); +} + ++ (BGEvent *)unknownPast { + return BGUnknownPast; +} + +- (instancetype _Nonnull)initWithImpulse:(NSString *)impulse sequence:(NSUInteger)sequence timestamp:(NSDate * _Nonnull)timestamp { + self = [super init]; + _impulse = impulse; + _sequence = sequence; + _timestamp = timestamp; + return self; +} + +- (BOOL)happenedSince:(NSUInteger)since { + return _sequence > 0 && _sequence >= since; +} + +- (NSString *)description { + return self.debugDescription; +} + +- (NSString *)debugDescription { + return [NSString stringWithFormat:@"<%@:%p (%lu), %@>", NSStringFromClass(self.class), self, (unsigned long)self.sequence, self.impulse]; +} + +- (NSString *)debugLine { + return [NSString stringWithFormat:@"Event: (%lu), %@", (unsigned long)_sequence, _impulse]; +} + +@end + + +@implementation BGResource +@dynamic traced; +@dynamic valuePersistence; + +- (instancetype)initWithExtent:(BGExtent *)extent { + return [self initWithExtent:extent value:nil event:nil]; +} + +- (instancetype)initWithExtent:(BGExtent *)extent value:(id)value event:(BGEvent *)event { + self = [super init]; + _subsequents = [NSHashTable weakObjectsHashTable]; + _value = value; + _event = event; + [extent addResource:self]; + return self; +} + +- (BOOL)justUpdated { + return [self justUpdated:nil useTo:NO from:nil useFrom:NO]; +} + +- (BOOL)justUpdatedTo:(id _Nullable)toValue { + return [self justUpdated:toValue useTo:YES from:nil useFrom:NO]; +} + +- (BOOL)justAdded { + return _graph && _added && _added == _graph.lastEvent; +} + +- (BOOL)hasUpdated { + return _graph && _event && _event != BGUnknownPast; +} + +- (BOOL)traceHasUpdated { + BGEvent *traceEvent; + return _graph && (traceEvent = self.traceEvent) && traceEvent != BGUnknownPast; +} + +- (BOOL)hasUpdatedSince:(BGResource *)since { + return self.event && self.event.sequence >= since.event.sequence; +} + +- (id)traceValue { + return self.traced && _event == _graph.currentEvent ? _previousValue : _value; +} + +- (BGEvent *)traceEvent { + return self.traced && _event == _graph.currentEvent ? _previousEvent : _event; +} + +- (BOOL)justUpdated:(id)toValue useTo:(BOOL)useTo from:(id _Nullable)fromValue useFrom:(BOOL)useFrom { + if (_graph.currentEvent == nil || self.event != _graph.currentEvent) { + return NO; + } + if (useTo && !bg_equal(self.value, toValue)) { + return NO; + } + if (useFrom && !bg_equal(self.traceValue, fromValue)) { + return NO; + } + return YES; +} + +- (void)notifySubsequents { + for (BGBehavior *subsequent in _subsequents) { + [_graph submitToQueue:subsequent]; + } +} + +- (BOOL)assertUpdateable { + NSAssert(_extent.addedToGraph, @"A resource can only be updated after its been added to a graph."); + NSAssert(_graph.currentEvent, @"A resources's value can only be updated during an event loop."); + NSAssert(_behavior ? _behavior == _graph.currentBehavior : YES, @"A resource's value can only be updated while its behavior is responding."); + NSAssert(!_behavior ? _graph.currentBehavior == nil : YES, @"A non supplied resource can only be updated at the start of a new event loop inside a submitChanges block."); + return YES; +} + +- (void)_updateValue:(id)value { + NSAssert([self assertUpdateable], @"Cannot update"); + if (!bg_equal(_value, value)) { + [self _forceUpdateValue:value]; + } +} + +- (void)_forceUpdateValue:(id)value { + NSAssert([self assertUpdateable], @"Cannot update"); + + if (self.traced) { + if (_previousEvent.sequence < self.graph.sequence) { + _previousValue = _value; + _previousEvent = _event; + } + } else { + if (_value) { + [self.graph.deferredRelease addObject:_value]; + } + _previousValue = nil; + _previousEvent = nil; + } + + + _value = value; + _event = _graph.currentEvent; + [self notifySubsequents]; + [self logUpdate]; + + if (self.valuePersistence != BGResourcePersistent) { + [_graph trackTransient:self]; + } +} + +- (void)clearTransient { + switch (self.valuePersistence) { + case BGResourceTransient: + if (_value) { + [self.graph.deferredRelease addObject:_value]; + } + _value = nil; + break; + case BGResourceTransientTrace: + if (_previousValue) { + [self.graph.deferredRelease addObject:_previousValue]; + } + _previousValue = nil; + break; + case BGResourcePersistent: + break; + } +} + +- (void)logUpdate { + if (@available(ios 12, *)) { + os_signpost_id_t eventSid = os_signpost_id_generate(_graph.splog); + os_signpost_event_emit(_graph.splog, eventSid, "resource updated", "name=\"%@\" value=\"%@\"", self.staticDebugName, self.value); + } + os_log_debug(_graph.aclog, " - %@ => %@ (%@(%p))", _staticDebugName, _value, NSStringFromClass([_extent class]), _extent); +} + +- (NSString *)description { + return [self debugDescription]; +} + +- (NSString *)debugDescription { + return [NSString stringWithFormat:@"<%@:%p (%@) value=%@>", NSStringFromClass(self.class), self, self.staticDebugName, _value]; +} + +- (NSString *)debugLine { + return [NSString stringWithFormat:@" %@ (%lu): %@", self.staticDebugName, (unsigned long)_event.sequence, _value]; +} + +@end + +@implementation BGMoment + +- (void)update { + [self _forceUpdateValue:nil]; +} + +- (void)updateValue:(id)value { + [self _forceUpdateValue:value]; +} + +- (void)logUpdate { + if (@available(ios 12, *)) { + if (os_signpost_enabled(_graph.splog)) { + os_signpost_id_t eventSid = os_signpost_id_generate(_graph.splog); + if (self.value) { + os_signpost_event_emit(_graph.splog, eventSid, "BGMoment happened", "name=\"%@\" value=\"%@\"", self.staticDebugName, self.value); + } else { + os_signpost_event_emit(_graph.splog, eventSid, "BGMoment happened", "name=\"%@\"", self.staticDebugName); + } + } + } + os_log_debug(_graph.aclog, " - %@ => %@ (%@(%p))", _staticDebugName, self.value, NSStringFromClass([_extent class]), _extent); +} + +- (BOOL)traced { + return NO; +} + +- (BGResourceValuePersistence)valuePersistence { + return BGResourceTransient; +} + +@end + +@implementation BGState +@synthesize valuePersistence = _valuePersistence; + +- (instancetype)initWithExtent:(BGExtent *)extent { + return [self initWithExtent:(BGExtent *)extent value:nil]; +} + +- (instancetype)initWithExtent:(BGExtent *)extent value:(id _Nullable)value { + return [super initWithExtent:extent value:value event:BGUnknownPast]; +} + +- (BGResourceValuePersistence)valuePersistence { + return BGResourceTransientTrace; +} + +- (BOOL)traced { + return YES; +} + +- (BOOL)justUpdatedFrom:(id _Nullable)fromValue { + return [self justUpdated:nil useTo:NO from:fromValue useFrom:YES]; +} + +- (BOOL)justUpdatedTo:(id _Nullable)toValue from:(id _Nullable)fromValue { + return [self justUpdated:toValue useTo:YES from:fromValue useFrom:YES]; +} + +- (void)updateValue:(id)value { + [self _updateValue:value]; +} + +- (void)updateValueForce:(id)value { + [self _forceUpdateValue:value]; +} + +@end + + +@implementation BGBehavior + +- (instancetype _Nonnull)initWithExtent:(BGExtent *)extent + demands:(NSArray * _Nullable)demands + supplies:(NSArray * _Nullable)supplies + runBlock:(void (^ _Nullable)(BGExtent * _Nonnull extent))runBlock { + self = [super init]; + _extent = extent; + _runBlock = runBlock; + _demands = [NSHashTable weakObjectsHashTable]; + _supplies = [NSHashTable new]; + [self setDemands:demands]; + [self setSupplies:supplies]; + [extent addBehavior:self]; + return self; +} + + +- (NSString *)description { + return [self debugDescription]; +} + +- (void)setExtent:(BGExtent *)extent { + _extent = extent; +} + +- (NSString *)debugDescription { + NSString *suppliesString = _supplies.count == 0 ? @"{}" : ({ + NSMutableString *string = [NSMutableString stringWithString:@"{"]; + for (BGResource *supply in _supplies) { + [string appendFormat:@"\n\t\t%@", supply]; + } + [string appendString:@"\n}"]; + string; + }); + return [NSString stringWithFormat:@"<%@:%p (%@) supplies=%@>", NSStringFromClass(self.class), self, self.staticDebugName, suppliesString]; +} + +- (NSString *)debugLine { + NSMutableArray *sups = [NSMutableArray new]; + for (BGResource *supply in _supplies) { + [sups addObject:supply.staticDebugName]; + } + return [NSString stringWithFormat:@"| %@ >", [sups componentsJoinedByString:@","]]; +} + +- (NSString *)debugCurrentState { + NSMutableArray *info = [NSMutableArray new]; + [info addObject:[_graph.currentEvent debugLine]]; + [info addObject:@"Demands:"]; + for (BGResource *demand in _demands) { + [info addObject:[demand debugLine]]; + } + [info addObject:@"Supplies:"]; + for (BGResource *supply in _supplies) { + [info addObject:[supply debugLine]]; + } + return [info componentsJoinedByString:@"\n"]; +} + +- (void)setDemands:(NSArray * _Nullable)demands { + NSAssert(self.extent.addedToGraph == nil || self.graph.processingChanges, @"Demands can only be modified before adding the behavior to the graph or during an event."); + + _modifiedDemands = [demands mutableCopy]; + [_graph.modifiedDemands addObject:self]; +} + +- (void)addDemand:(BGResource * _Nonnull)demand { + NSAssert(self.extent.addedToGraph == nil || self.graph.processingChanges, @"Demands can only be modified before adding the behavior to the graph or during an event."); + + if (!demand) { + // useful instead of having to do the if check everywhere you want to add it + // although in theory if you meant to add something but were adding nil then you wouldn't be alerted to it + return; + } + + if (_modifiedDemands) { + if (![_modifiedDemands containsObject:demand]) { + [_modifiedDemands addObject:demand]; + [_graph.modifiedDemands addObject:self]; + } + } else { + if (![_demands containsObject:demand]) { + _modifiedDemands = [_demands.allObjects mutableCopy]; + [_modifiedDemands addObject:demand]; + [_graph.modifiedDemands addObject:self]; + } + } +} + +- (void)removeDemand:(BGResource * _Nonnull)demand { + NSAssert(self.extent.addedToGraph == nil || self.graph.processingChanges, @"Demands can only be modified before adding the behavior to the graph or during an event."); + + if (_modifiedDemands) { + if ([_modifiedDemands containsObject:demand]) { + [_modifiedDemands removeObject:demand]; + [_graph.modifiedDemands addObject:self]; + } + } else { + if ([_demands containsObject:demand]) { + _modifiedDemands = [_demands.allObjects mutableCopy]; + [_modifiedDemands removeObject:demand]; + [_graph.modifiedDemands addObject:self]; + } + } +} + +- (void)setSupplies:(NSArray * _Nullable)supplies { + NSAssert(self.extent.addedToGraph == nil || self.graph.processingChanges, @"Supplies can only be modified before adding the behavior to the graph or during an event."); + + for (BGResource *supply in _supplies) { + if (![supplies containsObject:supply]) { + // Removed supply + supply.behavior = nil; + } + } + + for (BGResource *supply in supplies) { + if (![_supplies containsObject:supply]) { + // Added supply + NSAssert(!supply.behavior, @"Supply already added to a different behavior."); + supply.behavior = self; + + for (BGBehavior *subsequent in supply.subsequents) { + [self.graph.modifiedDemands addObject:subsequent]; + } + } + } + + [_supplies removeAllObjects]; + for (BGResource *supply in supplies) { + NSAssert(supply.behavior == self, nil); + [_supplies addObject:supply]; + } +} + +@end + +@implementation BGAction + +- (instancetype)initWithName:(NSString *)name block:(dispatch_block_t)block { + self = [super init]; + _name = name; + _block = block; + return self; +} + +@end + +@implementation BGSideEffect + +- (instancetype)initWithName:(NSString *)name event:(BGEvent *)event { + NSAssert(self.class != BGSideEffect.class, @"Abstract"); + return self; +} + +- (void)run { + NSAssert(NO, @"Abstract"); +} + +- (NSString *)description { + return self.debugDescription; +} + +- (NSString *)debugDescription { + return [NSString stringWithFormat:@"<%@:%p name=%@ event=%@>", NSStringFromClass(self.class), self, _name, _event]; +} + +@end + +@implementation BGBehaviorSideEffect + +- (instancetype)initWithName:(NSString *)name event:(BGEvent *)event extent:(BGExtent *)extent block:(void (^)(BGExtent * _Nullable))block { + self = [super init]; + _name = name; + _event = event; + _extent = extent; + _block = block; + return self; +} + +- (void)run { + _block(_extent); +} + +@end + +@implementation BGGraphSideEffect + +- (instancetype)initWithName:(NSString *)name event:(BGEvent *)event block:(dispatch_block_t)block { + self = [super init]; + _name = name; + _event = event; + _block = block; + return self; +} + +- (void)run { + _block(); +} + +@end + +@implementation BGEventLoopState + +- (NSUInteger)sequence { + return _event.sequence; +} + +@end + +@implementation BGGraph + ++ (void)initialize { + if (self == BGGraph.class) { + NullPushedValue = [NSObject new]; + } +} + +- (instancetype)init { + self = [super init]; + + NSString *subsystem = [NSBundle mainBundle].bundleIdentifier; + if ([[[NSProcessInfo processInfo] arguments] containsObject:@"-signpostBehaviorGraphActivity"]) { + _splog = os_log_create(subsystem.UTF8String, "bg-signpost"); + } else { + _splog = OS_LOG_DISABLED; + } + if ([[[NSProcessInfo processInfo] arguments] containsObject:@"-logBehaviorGraphActivity"]) { + _aclog = os_log_create(subsystem.UTF8String, "bg-log"); + } else { + _aclog = OS_LOG_DISABLED; + } + if (@available(iOS 12, *)) { + os_signpost_event_emit(_splog, os_signpost_id_generate(_splog), "graph created", "id=%p", self); + } + os_log_debug(_aclog, "graph created: id=%p", self); + + _behaviorQueue = [[BGPriorityQueue alloc] initWithComparisonBlock:^CFComparisonResult(BGBehavior * _Nonnull obj1, BGBehavior * _Nonnull obj2) { + if (obj1.order < obj2.order) { + return kCFCompareLessThan; + } else if (obj1.order > obj2.order) { + return kCFCompareGreaterThan; + } else { + return kCFCompareEqualTo; + } + }]; + + _actionQueue = [NSMutableArray new]; + _sideEffectQueue = [NSMutableArray new]; + + _untrackedBehaviors = [NSMutableSet new]; + _modifiedDemands = [NSMutableSet new]; + _updatedTransientResources = [NSMutableArray new]; + _deferredRelease = [NSMutableArray new]; + _needsOrdering = [NSMutableSet new]; + + _rootExtent = [[BGExtent alloc] initWithGraph:self]; + _currentEventResource = [_rootExtent stateWithValue:nil]; + _currentEventResource.staticDebugName = @"currentEventResource"; + [self addExtent:_rootExtent event:BGUnknownPast]; + + return self; +} + +- (void)action:(NSString * _Nullable)impulse runBlock:(dispatch_block_t _Nonnull)changes { + [self action:impulse requireSync:_defaultRequireSync runBlock:changes]; +} + +- (void)action:(NSString *)impulse requireSync:(BOOL)requireSync runBlock:(dispatch_block_t)changes { + [self _action:impulse requireSync:requireSync changes:changes]; +} + +- (void)_action:(NSString *)impulse requireSync:(BOOL)requireSync changes:(dispatch_block_t)changes { + if (self.processingAction) { + NSAssert(!requireSync, @"Cannot synchronously complete nested action. Either relax the synchronous requirement for this action or fold changes into current action."); + requireSync = NO; + } + + NSAssert(!(self.assertOnLeakedSideEffects && self.processingChanges), @"Side effect leaked while processing changes."); + + BGAction *action = [[BGAction alloc] initWithName:impulse block:changes]; + [_actionQueue addObject:action]; + + if (_eventLoopDrivers == 0 || requireSync) { + [self eventLoop]; + } +} + +- (void)eventLoop { + ++_eventLoopDrivers; + while (YES) { + @autoreleasepool { + if (_eventLoopState.processingChanges) { + if (_untrackedBehaviors.count > 0) { + [self addUntrackedBehaviors]; + } + + if (_modifiedDemands.count > 0) { + [self commitModifiedDemands]; + } + + if (_needsOrdering.count > 0) { + [self orderBehaviors]; + } + + if (_behaviorQueue.count > 0) { + BGBehavior *subsequent = [_behaviorQueue pop]; + [self runBehavior:subsequent]; + continue; + } + } + + _eventLoopState.processingChanges = NO; + + if (_sideEffectQueue.count > 0) { + BGSideEffect *sideEffect = _sideEffectQueue[0]; + [_sideEffectQueue removeObjectAtIndex:0]; + [sideEffect run]; + continue; + } + + if (_updatedTransientResources.count > 0) { + [self clearUpdatedTransientResources]; + continue; + } + + if (_deferredRelease.count > 0) { + // Retaining any objects that might be going to nil until the end of the event loop + // This limits ways that resource updates and clearing transients might cause + // deallocs which could potentially force new events during the update phase + [_deferredRelease removeAllObjects]; + continue; + } + + if (_eventLoopState) { + NSAssert(!self.processingAction && !self.processingChanges, nil); + + BGEventLoopState *eventLoopState = _eventLoopState; + _eventLoopState = nil; + + if (@available(ios 12, *)) { + os_signpost_interval_end(_splog, eventLoopState.eventSid, "event loop"); + } + } + + if (_actionQueue.count > 0) { + NSDate *timestamp = [_dateProvider bg_currentDate] ?: [NSDate date]; + + BGAction *action = _actionQueue[0]; + [_actionQueue removeObjectAtIndex:0]; + + BGEvent *event = [[BGEvent alloc] initWithImpulse:action.name sequence:(_lastEvent.sequence + 1) timestamp:timestamp]; + _lastEvent = event; + + _eventLoopState = [BGEventLoopState new]; + _eventLoopState.event = event; + _eventLoopState.processingAction = YES; + _eventLoopState.processingChanges = YES; + + if (@available(ios 12, *)) { + _eventLoopState.eventSid = os_signpost_id_generate(_splog); + os_signpost_interval_begin(_splog, _eventLoopState.eventSid, "event loop", "impulse=\"%@\" sequence=%lu timestamp=\"%@\"", event.impulse, (unsigned long)event.sequence, event.timestamp); + } + os_log_debug(_aclog, "=== event %@ sequence=%lu timestamp=%@ ===", event.impulse, (unsigned long)event.sequence, event.timestamp); + + action.block(); + [_currentEventResource updateValueForce:event]; + + _eventLoopState.processingAction = NO; + + // NOTE: We keep the action block around because it may capture capture and retain some external objects + // If it were to go away right after running then that might cause a dealloc to be called as it goes out of scope internal + // to the event loop and thus create a side effect during the update phase. + // So we keep it around until after all updates are processed. + [_deferredRelease addObject:action]; + + continue; + } + break; + } + } + --_eventLoopDrivers; +} + +- (BGEvent *)currentEvent { + return _eventLoopState.event; +} + +- (BOOL)processingChanges { + return _eventLoopState.processingChanges; +} + +- (BOOL)processingAction { + return _eventLoopState.processingAction; +} + +- (NSUInteger)sequence { + return _eventLoopState.sequence; +} + +- (void)submitToQueue:(BGBehavior *)behavior { + // @SAL 8/26/2019-- I'm not sure how either of these would trigger, it seems they are both a result of a broken + // algorithm, not a misconfigured graph + // jlou 2/5/19 - These asserts are checking for graph implementation bugs, not for user error. + NSAssert(self.processingChanges, @"Should not be activating behaviors in current phase."); + NSAssert(behavior.lastUpdateSequence != _eventLoopState.sequence, @"Behavior already ran."); + if (behavior.enqueuedSequence < self.sequence) { + behavior.enqueuedSequence = self.sequence; + [_behaviorQueue push:behavior]; + } +} + +- (void)runBehavior:(BGBehavior *)behavior { + // jlou 2/5/19 - This assert checks for graph implementation bugs, not for user error. + NSAssert(behavior.lastUpdateSequence < self.sequence, @"Behaviors should only run once per cycle."); + if (behavior.removedSequence != self.sequence) { + _currentBehavior = behavior; + behavior.lastUpdateSequence = self.sequence; + if (behavior.runBlock) { + unsigned long long behaviorSid = 0; + if (@available(iOS 12, *)) { + behaviorSid = os_signpost_id_generate(_splog); + os_signpost_interval_begin(_splog, behaviorSid, "behavior run begin", "name=\"%@\"", [behavior debugLine]); + } + os_log_debug(_aclog, " %@ (%@(%p))", [behavior debugLine], NSStringFromClass([behavior.extent class]), behavior.extent); + + behavior.runBlock(behavior.extent); + if (@available(iOS 12, *)) { + os_signpost_interval_end(_splog, behaviorSid, "behavior run end"); + } + } + _currentBehavior = nil; + } +} + +- (void)sideEffect:(NSString *)name runBlock:(dispatch_block_t)block { + __auto_type sideEffect = [[BGGraphSideEffect alloc] initWithName:name event:self.currentEvent block:block]; + [self submitSideEffect:sideEffect]; +} + +- (void)submitSideEffect:(BGSideEffect * _Nonnull)sideEffect { + NSAssert(self.processingChanges, @"Can only submit an after-changes block during a graph cycle."); + [_sideEffectQueue addObject:sideEffect]; +} + +- (void)addUntrackedBehaviors { + for (BGBehavior *behavior in _untrackedBehaviors) { + [_modifiedDemands addObject:behavior]; + [self submitToQueue:behavior]; + } + [_untrackedBehaviors removeAllObjects]; +} + +- (void)commitModifiedDemands { + for (BGBehavior *subsequent in _modifiedDemands) { + NSMutableSet *addedDemands; + NSMutableSet *removedDemands; + if (subsequent.modifiedDemands) { + for (BGResource *demand in subsequent.demands) { + if (![subsequent.modifiedDemands containsObject:demand]) { + if (!removedDemands) { + removedDemands = [NSMutableSet new]; + } + [removedDemands addObject:demand]; + } + } + + for (BGResource *demand in subsequent.modifiedDemands) { + NSAssert(demand.graph == self && demand.extent.addedToGraph != nil, @"Added demands must be added to the graph."); + if (![subsequent.demands containsObject:demand]) { + if (!addedDemands) { + addedDemands = [NSMutableSet new]; + } + [addedDemands addObject:demand]; + } + } + + for (BGResource *demand in removedDemands) { + [demand.subsequents removeObject:subsequent]; + [subsequent.demands removeObject:demand]; + } + + for (BGResource *demand in addedDemands) { + [demand.subsequents addObject:subsequent]; + [subsequent.demands addObject:demand]; + } + } + + BOOL needsOrdering = (subsequent.orderingState == BGOrderingStateUnordered); + if (!needsOrdering) { + for (BGResource *demand in subsequent.demands) { + BGBehavior *orderedPrior = (BGBehavior *)demand.behavior; + if (orderedPrior.orderingState == BGOrderingStateOrdered && orderedPrior.order >= subsequent.order) { + needsOrdering = YES; + } + } + } + + if (needsOrdering) { + [_needsOrdering addObject:subsequent]; + } + + subsequent.modifiedDemands = nil; + } + + [_modifiedDemands removeAllObjects]; +} + +- (void)orderBehaviors { + __auto_type needsOrdering = [NSMutableArray new]; + + // Walk subsequents and add to needs ordering list + { + __auto_type traversalQueue = [NSMutableArray new]; + + // Add unsorted behaviors to traversal queue and temporarily mark each as 'ordered' + // so that it will be traversed when first encountered. + for (BGBehavior *behavior in _needsOrdering) { + behavior.orderingState = BGOrderingStateOrdered; + [traversalQueue addObject:behavior]; + } + [_needsOrdering removeAllObjects]; + + while (traversalQueue.count > 0) { + BGBehavior *behavior = traversalQueue[0]; + [traversalQueue removeObjectAtIndex:0]; + + if (behavior.orderingState != BGOrderingStateUnordered) { + behavior.orderingState = BGOrderingStateUnordered; + + [needsOrdering addObject:behavior]; + + for (BGResource *supply in behavior.supplies) { + for (BGBehavior *subsequent in supply.subsequents) { + [traversalQueue addObject:subsequent]; + } + } + } + } + } + + BOOL needsReheap = NO; + for (BGBehavior *behavior in needsOrdering) { + [self sortDFS:behavior needsReheap:&needsReheap]; + } + + if (needsReheap) { + [_behaviorQueue needsResort]; + } +} + +- (void)clearUpdatedTransientResources { + while (_updatedTransientResources.count > 0) { + BGResource *rez = [_updatedTransientResources objectAtIndex:0]; + [_updatedTransientResources removeObjectAtIndex:0]; + [rez clearTransient]; + } +} + +- (NSString *)cycleStringForBehavior:(BGBehavior *)behavior { + NSMutableArray *stack = [NSMutableArray new]; + BOOL found = [self cyclePrinterDFSCurrent:behavior target:behavior resourceStack:stack]; + if (found) { + NSMutableArray *output = [NSMutableArray new]; + while (stack.count > 0) { + BGResource *resource = [stack lastObject]; + [stack removeLastObject]; + [output addObject:[NSString stringWithFormat:@"| (%@) %@ >", + NSStringFromClass(resource.behavior.extent.class), resource.staticDebugName ?: resource.debugDescription]]; + } + NSMutableArray *behaviorSupplies = [NSMutableArray new]; + for (BGResource *resource in behavior.supplies) { + [behaviorSupplies addObject:resource.staticDebugName ?: resource.debugDescription]; + } + NSString *outputLine = [NSString stringWithFormat:@"| (%@) %@ >", + NSStringFromClass(behavior.extent.class), [behaviorSupplies componentsJoinedByString:@","]]; + [output addObject:outputLine]; + return [output componentsJoinedByString:@"\n"]; + } else { + // no cycle found + return nil; + } +} + +- (BOOL)cyclePrinterDFSCurrent:(BGBehavior *)currentBehavior target:(BGBehavior *)targetBehavior resourceStack:(NSMutableArray *)stack { + for (BGResource *resource in currentBehavior.demands) { + [stack addObject:resource]; + if (resource.behavior == targetBehavior) { + return YES; // cycle detected + } + if ([self cyclePrinterDFSCurrent:resource.behavior target:targetBehavior resourceStack:stack]) { + return YES; + } + [stack removeLastObject]; + } + return NO; +} + +- (void)sortDFS:(BGBehavior * _Nonnull)behavior needsReheap:(BOOL * _Nonnull)needsReheap { + NSAssert(behavior.orderingState != BGOrderingStateOrdering, @"Dependency cycle detected:\n%@", [self cycleStringForBehavior:behavior]); + if (behavior.orderingState == BGOrderingStateUnordered) { + behavior.orderingState = BGOrderingStateOrdering; + NSUInteger order = PriorlessOrder + 1; + for (BGResource *demand in behavior.demands) { + BGBehavior * orderedPrior = demand.behavior; + if (orderedPrior.orderingState != BGOrderingStateOrdered) { + [self sortDFS:orderedPrior needsReheap:needsReheap]; + } + order = MAX(order, orderedPrior.order + 1); + } + behavior.orderingState = BGOrderingStateOrdered; + if (order != behavior.order) { + behavior.order = order; + *needsReheap = YES; + } + } +} + +- (void)removeBehavior:(BGBehavior *)behavior { + for (BGResource *supply in behavior.supplies) { + for (BGBehavior * subsequent in supply.subsequents) { + [subsequent.demands removeObject:supply]; + } + [supply.subsequents removeAllObjects]; + } + + BGBehavior * subsequent = (BGBehavior *)behavior; + for (BGResource *demand in subsequent.demands) { + [demand.subsequents removeObject:subsequent]; + } + [subsequent.demands removeAllObjects]; + + behavior.removedSequence = self.sequence; +} + +- (void)addExtent:(BGExtent *)extent event:(BGEvent *)event { + NSAssert(extent.addedToGraph == nil, @"Extent cannot be added to the graph twice."); + extent.addedToGraph = event; + for (BGResource *resource in extent.allResources.allObjects) { + resource.added = event; + } + for (BGBehavior * behavior in extent.allBehaviors.allObjects) { + [_untrackedBehaviors addObject:behavior]; + } +} + +- (void)removeExtent:(BGExtent *)extent { + NSAssert(self.processingChanges, @"Extents must be removed during an event."); + NSAssert(extent.addedToGraph != nil, @"Extent cannot be removed from graph twice."); + for (BGBehavior * behavior in extent.allBehaviors) { + [self removeBehavior:behavior]; + } + extent.addedToGraph = nil; +} + +- (void)trackTransient:(BGResource *)rez { + [_updatedTransientResources addObject:rez]; +} + +@end + +@interface YVSelector : NSObject +@property (nonatomic) NSString *name; +@property (nonatomic) SEL selector; +@end + +@implementation YVSelector +- (NSString *)description { + return [self debugDescription]; +} + +- (NSString *)debugDescription { + return [NSString stringWithFormat:@"<%@:%p %@>", NSStringFromClass(self.class), self, _name]; +} + +- (NSUInteger)hash { + return [_name hash]; +} + +- (BOOL)isEqual:(id)object { + return [_name isEqual:object]; +} +@end + +@implementation BGExtent + +static char kDemandableSelectorsKey; +static char kNodeableSelectorsKey; + + +- (NSString *)debugHere { + return [self.graph.currentBehavior debugCurrentState]; +} + +- (void)dealloc { + // @SAL 8/29/2019-- Removing is a bit tricky right now. If the signal to remove is the dealloc of the extent + // then we need to capture the allBehaviors before starting submitChanges otherwise it goes away + // with extent and then we can't access them. + // Possibly dealloc shouldn't be the signal (but it might be error prone to not use it). Its hard to model + // when the dealloc happens and we are specifically trying to keep track of those details. + + NSSet *allBehaviors = self->_allBehaviors; // save pointer so it won't disappear on us + BGGraph *graph = self.graph; + [self.graph action:_fname requireSync:NO runBlock:^{ + for (BGBehavior * behavior in allBehaviors) { + [graph removeBehavior:behavior]; + } + }]; +} + +- (instancetype _Nonnull)initWithGraph:(BGGraph *)graph { + if (self = [super init]) { + _graph = graph; + _allBehaviors = [NSMutableSet new]; + _allResources = [NSMutableSet new]; + } + return self; +} + +- (void)addToGraph { + NSAssert(_graph.eventLoopState.processingChanges, @"Extents must be added to a graph during an event."); + [self nameComponents]; + [_graph addExtent:self event:_graph.currentEvent]; +} + +- (void)removeFromGraph { + // @SAL 8/29/2019-- See dealloc for alternate removal process because of memory complications + [_graph removeExtent:self]; +} + +- (void)addBehavior:(BGBehavior *)behavior { + NSAssert(_addedToGraph == nil, @"Cannot add behavior after extent has been added to graph."); + NSAssert(behavior.extent == nil || behavior.extent == self, @"Behavior can only belong to one extent"); + behavior.extent = self; + behavior.graph = self.graph; + [_allBehaviors addObject:behavior]; +} + +- (void)addResource:(BGResource *)resource { + NSAssert(_addedToGraph == nil, @"Cannot add resource after extent has been added to graph."); + NSAssert(resource.extent == nil || resource.extent == self, @"Resource can only belong to one extent"); + if (resource.extent == nil) { + resource.extent = self; + resource.graph = self.graph; + [_allResources addObject:resource]; + } + +} + +- (BGBehavior * _Nonnull)behaviorWithDemands:(NSArray * _Nullable)demands + supplies:(NSArray * _Nullable)supplies + runBlock:(void(^_Nullable)(id _Nonnull extent))runBlock { + BGBehavior *bhv = [[BGBehavior alloc] initWithExtent:self demands:demands supplies:supplies runBlock:runBlock]; + return bhv; +} + +- (void)nameComponents { + + NSArray *nodeableSelectors = objc_getAssociatedObject([self class], &kNodeableSelectorsKey); + NSArray *demandableSelectors = objc_getAssociatedObject([self class], &kDemandableSelectorsKey); + + for (YVSelector *selector in nodeableSelectors) { + IMP implementation = [self methodForSelector:selector.selector]; + BGBehavior *(*function)(id, SEL) = (void *)implementation; + BGBehavior * behavior = function(self, selector.selector); + NSAssert(behavior, @"Process not initialized (%@)", selector.name); + if (behavior) { + if (behavior.staticDebugName == nil) { + behavior.staticDebugName = selector.name; + } + } + } + + for (YVSelector *selector in demandableSelectors) { + IMP implementation = [self methodForSelector:selector.selector]; + BGResource *(*function)(id, SEL) = (void *)implementation; + BGResource *resource = function(self, selector.selector); + NSAssert(resource, @"Resource not initialized (%@)", selector.name); + if (resource) { + if (resource.staticDebugName == nil) { + resource.staticDebugName = selector.name; + } + } + } +} + +- (void)sideEffect:(NSString *)name runBlock:(void (^)(id _Nonnull))block { + __auto_type sideEffect = [[BGBehaviorSideEffect alloc] initWithName:name event:self.graph.currentEvent extent:self block:block]; + [self.graph submitSideEffect:sideEffect]; +} + +- (BGState * _Nonnull)stateWithValue:(id)value { + return [[BGState alloc] initWithExtent:self value:value]; +} + +- (BGMoment * _Nonnull)moment { + return [[BGMoment alloc] initWithExtent:self]; +} + +- (BGResource * _Nonnull)resource { + return [[BGResource alloc] initWithExtent:self]; +} + + ++ (void)initialize { + + NSMutableSet *demandableSelectors = [NSMutableSet new]; + // this captures in case we have superclass that has the demandables + // we count on initialize happening from superclass down + NSMutableSet *parentDemandableSelectors = objc_getAssociatedObject([self superclass], &kDemandableSelectorsKey); + if (parentDemandableSelectors.count > 0) { + [demandableSelectors addObjectsFromArray:parentDemandableSelectors.allObjects]; + } + NSMutableSet *nodeableSelectors = [NSMutableSet new]; + NSMutableSet *parentNodeableSelectors = objc_getAssociatedObject([self superclass], &kNodeableSelectorsKey); + if (parentNodeableSelectors.count > 0) { + [nodeableSelectors addObjectsFromArray:parentNodeableSelectors.allObjects]; + } + + unsigned int count; + objc_property_t *properties = class_copyPropertyList(self, &count); + for (unsigned int i = 0; i < count; i++) { + objc_property_t property = properties[i]; + + NSString *typeEncoding = ({ + char *typeEncodingCString = property_copyAttributeValue(property, "T"); + NSString *typeEncoding = [NSString stringWithCString:typeEncodingCString encoding:NSASCIIStringEncoding]; + free(typeEncodingCString); + typeEncoding; + }); + if ([typeEncoding hasPrefix:@"@"] && typeEncoding.length > 3) { + Class cls = NSClassFromString([typeEncoding substringWithRange:NSMakeRange(2, typeEncoding.length - 3)]); + + BOOL demandable = [cls isSubclassOfClass:BGResource.class]; + BOOL nodeable = [cls isSubclassOfClass:BGBehavior.class]; + + if (demandable || nodeable) { + NSString *getterMethodName = ({ + NSString *methodName; + char *getter = property_copyAttributeValue(property, "G"); // Getter + if (getter != NULL) { + methodName = [NSString stringWithCString:getter encoding:NSASCIIStringEncoding]; + } else { + methodName = [NSString stringWithCString:property_getName(property) encoding:NSASCIIStringEncoding]; + } + free(getter); + methodName; + }); + + YVSelector *selector = [YVSelector new]; + selector.name = getterMethodName; + selector.selector = NSSelectorFromString(selector.name); + + if (demandable) { + [demandableSelectors addObject:selector]; + } + if (nodeable) { + [nodeableSelectors addObject:selector]; + } + } + } + } + free(properties); + + objc_setAssociatedObject(self, &kNodeableSelectorsKey, nodeableSelectors, OBJC_ASSOCIATION_RETAIN_NONATOMIC); + objc_setAssociatedObject(self, &kDemandableSelectorsKey, demandableSelectors, OBJC_ASSOCIATION_RETAIN_NONATOMIC); +} + +@end diff --git a/doc-site/examples/objc/BGExamples/BehaviorGraph/BGPriorityQueue.h b/doc-site/examples/objc/BGExamples/BehaviorGraph/BGPriorityQueue.h new file mode 100644 index 0000000..403a1a2 --- /dev/null +++ b/doc-site/examples/objc/BGExamples/BehaviorGraph/BGPriorityQueue.h @@ -0,0 +1,18 @@ +// +// BGPriorityQueue.h +// YVideoSDK +// +// Created by James Lou on 6/9/19. +// Copyright © 2019 Yahoo. All rights reserved. +// + +#import + +@interface BGPriorityQueue : NSObject +@property (nonatomic, readonly, nullable) ObjectType top; +@property (nonatomic, readonly) NSUInteger count; +- (instancetype _Nonnull)initWithComparisonBlock:(CFComparisonResult(^ _Nullable)(ObjectType _Nonnull obj1, ObjectType _Nonnull obj2))comparisonFunction NS_DESIGNATED_INITIALIZER; +- (ObjectType _Nullable)pop; +- (void)push:(ObjectType _Nonnull)object; +- (void)needsResort; +@end diff --git a/doc-site/examples/objc/BGExamples/BehaviorGraph/BGPriorityQueue.m b/doc-site/examples/objc/BGExamples/BehaviorGraph/BGPriorityQueue.m new file mode 100644 index 0000000..52122f4 --- /dev/null +++ b/doc-site/examples/objc/BGExamples/BehaviorGraph/BGPriorityQueue.m @@ -0,0 +1,91 @@ +// +// BGPriorityQueue.m +// YVideoSDK +// +// Created by James Lou on 6/9/19. +// Copyright © 2019 Yahoo. All rights reserved. +// + +#import "BGPriorityQueue.h" + +#define ElementCount (CFBinaryHeapGetCount(_heap) + _unheapedElements.count) + +CFComparisonResult bg_priorityQueueCompare(const void *ptr1, const void *ptr2, void *context) { + CFComparisonResult(^comparisonBlock)(id _Nonnull, id _Nonnull) = *(__unsafe_unretained CFComparisonResult(^ *)(id _Nonnull, id _Nonnull))context; + return comparisonBlock((__bridge id)ptr1, (__bridge id)ptr2); +} + +@interface BGPriorityQueue () +@property (nonatomic, readonly, nonnull) CFBinaryHeapRef heap; +@property (nonatomic, readonly, nonnull) CFComparisonResult(^comparisonBlock)(id _Nonnull, id _Nonnull); +@property (nonatomic, readonly) CFBinaryHeapCompareContext compareContext; +@property (nonatomic, readonly) NSMutableArray *unheapedElements; +@end + +@implementation BGPriorityQueue + +- (instancetype)init { + return [self initWithComparisonBlock:nil]; +} + +- (instancetype)initWithComparisonBlock:(CFComparisonResult (^)(id _Nonnull, id _Nonnull))comparisonBlock { + _comparisonBlock = comparisonBlock; + + CFBinaryHeapCallBacks callbacks = { .compare = &bg_priorityQueueCompare}; + CFBinaryHeapCompareContext context = { .info = &_comparisonBlock }; + _heap = CFBinaryHeapCreate(kCFAllocatorDefault, 0, &callbacks, &context); + + _unheapedElements = [NSMutableArray new]; + return self; +} + +- (void)dealloc { + CFRelease(_heap); +} + +- (id _Nullable)top { + if (ElementCount == 0) { + return nil; + } + + [self heapify]; + return (__bridge_transfer id)CFBinaryHeapGetMinimum(_heap); +} + +- (id _Nullable)pop { + if (ElementCount == 0) { + return nil; + } + + [self heapify]; + id top = (__bridge_transfer id)CFBinaryHeapGetMinimum(_heap); + CFBinaryHeapRemoveMinimumValue(_heap); + return top; +} + +- (void)push:(id)object { + [_unheapedElements addObject:object]; +} + +- (NSUInteger)count { + return ElementCount; +} + +- (void)heapify { + if (_unheapedElements.count > 0) { + for (id obj in _unheapedElements) { + CFBinaryHeapAddValue(_heap, (__bridge_retained void *)obj); + } + [_unheapedElements removeAllObjects]; + } +} + +- (void)needsResort { + while (CFBinaryHeapGetCount(_heap) > 0) { + id value = (__bridge_transfer id)CFBinaryHeapGetMinimum(_heap); + CFBinaryHeapRemoveMinimumValue(_heap); + [_unheapedElements addObject:value]; + } +} + +@end diff --git a/doc-site/examples/objc/BGExamples/BehaviorGraph/BGProfiler.h b/doc-site/examples/objc/BGExamples/BehaviorGraph/BGProfiler.h new file mode 100644 index 0000000..6d2c245 --- /dev/null +++ b/doc-site/examples/objc/BGExamples/BehaviorGraph/BGProfiler.h @@ -0,0 +1,25 @@ +// +// BGBehaviorGraphProfiler.h +// YVideoSDK +// +// Created by James Lou on 6/10/19. +// Copyright © 2019 Yahoo. All rights reserved. +// + +#if DEBUG + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface BGProfiler : NSObject +@property (nonatomic, readonly, class) BGProfiler *sharedInstance; +@property (nonatomic, readonly, class) BOOL testUndeclaredDemands; +@property (nonatomic, readonly, class) BOOL foundUndeclaredDemands; +- (NSString *)cycleTimeStats; +- (NSString *)sortTimeStats; +@end + +NS_ASSUME_NONNULL_END + +#endif diff --git a/doc-site/examples/objc/BGExamples/BehaviorGraph/BGProfiler.m b/doc-site/examples/objc/BGExamples/BehaviorGraph/BGProfiler.m new file mode 100644 index 0000000..2f00cf5 --- /dev/null +++ b/doc-site/examples/objc/BGExamples/BehaviorGraph/BGProfiler.m @@ -0,0 +1,334 @@ +// +// BGProfiler.m +// YVideoSDK +// +// Created by James Lou on 6/10/19. +// Copyright © 2019 Yahoo. All rights reserved. +// + +#if DEBUG + +#import "BGProfiler.h" +#import "BGGraph+Private.h" + +#import +#include + +#define NS_PER_MS 1000000.0 + + +static BOOL assertUndeclaredDemands; +static BOOL testUndeclaredDemands; +static BOOL foundUndeclaredDemands; + +@interface BGCycleStats : NSObject +@property (nonatomic) uint64_t totalTime; +@property (nonatomic) uint64_t count; +@property (nonatomic) uint64_t totalSortTime; +@property (nonatomic) uint64_t sortCount; +@end + +@implementation BGCycleStats +@end + +@interface BGSortStats : NSObject +@property (nonatomic) uint64_t totalTime; +@property (nonatomic) uint64_t count; +@end + +@implementation BGSortStats +@end + +@interface BGProfiler () + +@property (nonatomic, readonly) NSMutableDictionary *cycleStats; +@property (nonatomic, readonly) uint64_t totalCycleTime; +@property (nonatomic, readonly) uint64_t cycleCount; + +@property (nonatomic, readonly) NSMutableDictionary *sortStats; +@property (nonatomic, readonly) uint64_t totalSortTime; +@property (nonatomic, readonly) uint64_t sortCount; + +@property (nonatomic, readonly) NSMutableArray *currentCycleSortTimes; + +- (void)addCycleWithImpulse:(NSString *)impulse time:(uint64_t)time; +- (void)addSortWithUnsortedCount:(uint64_t)unsortedCount time:(uint64_t)time; +@end + +@interface BGResource (Profiler) +@end + +@implementation BGResource (Profiler) + +- (void)profiler_verifyDemands { + // Looks at every access to ensure that things are being accessed properly in the graph. + BGBehavior *currentBehavior = self.behavior.graph.currentBehavior; + + if (currentBehavior && self.behavior != currentBehavior && ![currentBehavior.demands containsObject:self]) { + foundUndeclaredDemands = YES; + if (assertUndeclaredDemands) { + NSAssert(NO, @"Resource %@ (%p) must be a demanded or supplied by behavior %@ (%p) to read its value or event", + self.staticDebugName, self, currentBehavior.staticDebugName, currentBehavior); + } + } +} + +- (id)profiler_value { + [self profiler_verifyDemands]; + return [self profiler_value]; +} + +- (BGEvent *)profiler_event { + [self profiler_verifyDemands]; + return [self profiler_event]; +} + +@end + +@interface BGGraph () +- (void)orderBehaviors; +- (void)processChanges:(dispatch_block_t)changeBlock impulse:(NSString *)impulse; +@end + +@interface BGGraph (Profiler) +@end + +@implementation BGGraph (Profiler) + +- (void)profiler_processChanges:(dispatch_block_t _Nonnull)changeBlock impulse:(NSString * _Nonnull)impulse { + mach_timebase_info_data_t info; + mach_timebase_info(&info); + + uint64_t start = mach_absolute_time(); + [self profiler_processChanges:changeBlock impulse:impulse]; + uint64_t end = mach_absolute_time(); + + uint64_t duration = (end - start) * info.numer / info.denom; + [BGProfiler.sharedInstance addCycleWithImpulse:impulse time:duration]; +} + +- (void)profiler_orderBehaviors { + NSUInteger unsortedCount = self.needsOrdering.count; + if (unsortedCount > 0) { + mach_timebase_info_data_t info; + mach_timebase_info(&info); + + uint64_t start = mach_absolute_time(); + [self profiler_orderBehaviors]; + uint64_t end = mach_absolute_time(); + + uint64_t duration = (end - start) * info.numer / info.denom; + [BGProfiler.sharedInstance addSortWithUnsortedCount:unsortedCount time:duration]; + } else { + [self profiler_orderBehaviors]; + } +} + +@end + +@implementation BGProfiler + +static BGProfiler *sharedInstance; + ++ (void)load { + sharedInstance = [BGProfiler new]; + + if ([NSProcessInfo.processInfo.arguments containsObject:@"-graphProfileTime"]) { + { + Method original = class_getInstanceMethod(BGGraph.class, NSSelectorFromString(@"processChanges:impulse:")); + Method swizzled = class_getInstanceMethod(BGGraph.class, @selector(profiler_processChanges:impulse:)); + method_exchangeImplementations(original, swizzled); + } + + { + Method original = class_getInstanceMethod(BGGraph.class, @selector(orderBehaviors)); + Method swizzled = class_getInstanceMethod(BGGraph.class, @selector(profiler_orderBehaviors)); + method_exchangeImplementations(original, swizzled); + } + } + + assertUndeclaredDemands = [NSProcessInfo.processInfo.arguments containsObject:@"-graphVerifyDemands"]; + testUndeclaredDemands = [NSProcessInfo.processInfo.environment[@"test_undeclared_demands"] isEqualToString:@"1"]; + + if (assertUndeclaredDemands || testUndeclaredDemands) { + { + Method original = class_getInstanceMethod(BGResource.class, @selector(value)); + Method swizzled = class_getInstanceMethod(BGResource.class, @selector(profiler_value)); + method_exchangeImplementations(original, swizzled); + } + + { + Method original = class_getInstanceMethod(BGResource.class, @selector(event)); + Method swizzled = class_getInstanceMethod(BGResource.class, @selector(profiler_event)); + method_exchangeImplementations(original, swizzled); + } + } +} + ++ (BGProfiler *)sharedInstance { + return sharedInstance; +} + ++ (BOOL)testUndeclaredDemands { + return testUndeclaredDemands; +} + ++ (BOOL)foundUndeclaredDemands { + return foundUndeclaredDemands; +} + +- (instancetype)init { + _cycleStats = [NSMutableDictionary new]; + _sortStats = [NSMutableDictionary new]; + _currentCycleSortTimes = [NSMutableArray new]; + return self; +} + +- (void)addCycleWithImpulse:(NSString *)impulse time:(uint64_t)time { + impulse = impulse ?: @"none"; + BGCycleStats *stats = _cycleStats[impulse]; + if (!stats) { + stats = [BGCycleStats new]; + _cycleStats[impulse] = stats; + } + stats.totalTime += time; + ++stats.count; + + _totalCycleTime += time; + ++_cycleCount; + + for (NSNumber *sortTime in _currentCycleSortTimes) { + ++stats.sortCount; + stats.totalSortTime += sortTime.unsignedLongLongValue; + } + [_currentCycleSortTimes removeAllObjects]; +} + +- (void)addSortWithUnsortedCount:(uint64_t)unsortedCount time:(uint64_t)time { + BGSortStats *stats = _sortStats[@(unsortedCount)]; + if (!stats) { + stats = [BGSortStats new]; + _sortStats[@(unsortedCount)] = stats; + } + stats.totalTime += time; + ++stats.count; + + _totalSortTime += time; + ++_sortCount; + + [_currentCycleSortTimes addObject:@(time)]; +} + +- (NSString *)cycleTimeStats { + if (![[[NSProcessInfo processInfo] arguments] containsObject:@"-graphProfileTime"]) { + return @"Use run argument '-graphProfileTime' to enable behavior graph time profiling."; + } + + NSMutableArray *lines = [NSMutableArray new]; + + NSString *(^newLine)(NSString *, NSString *, NSString *, NSString *, NSString *, NSString *) = ^NSString *(NSString *name, NSString *averageTime, NSString *totalTime, NSString *count, NSString *sortTime, NSString *sortCount) { + NSMutableString *string = [NSMutableString new]; + [string appendString:name]; + for (int i = 0; i < 140 - (NSInteger)name.length - (NSInteger)averageTime.length; ++i) { + [string appendString:@" "]; + } + [string appendString:averageTime]; + + for (int i = 0; i < 20 - (NSInteger)totalTime.length; ++i) { + [string appendString:@" "]; + } + [string appendString:totalTime]; + + for (int i = 0; i < 20 - (NSInteger)count.length; ++i) { + [string appendString:@" "]; + } + [string appendString:count]; + + for (int i = 0; i < 20 - (NSInteger)sortTime.length; ++i) { + [string appendString:@" "]; + } + [string appendString:sortTime]; + + for (int i = 0; i < 20 - (NSInteger)sortCount.length; ++i) { + [string appendString:@" "]; + } + [string appendString:sortCount]; + + return string; + }; + + [lines addObject:newLine(@"Impulse", @"Avg (ms)", @"Total (ms)", @"Count", @"Sort Time", @"Sort Count")]; + for (NSString *name in [_cycleStats.allKeys sortedArrayUsingComparator:^NSComparisonResult(NSString * _Nonnull obj1, NSString * _Nonnull obj2) { + NSTimeInterval time1 = ({ BGCycleStats *stats = _cycleStats[obj1]; stats.totalTime / (double)stats.count; }); + NSTimeInterval time2 = ({ BGCycleStats *stats = _cycleStats[obj2]; stats.totalTime / (double)stats.count; }); + if (time1 > time2) { + return NSOrderedAscending; + } else if (time1 < time2) { + return NSOrderedDescending; + } else { + return NSOrderedSame; + } + }]) { + BGCycleStats *cycle = _cycleStats[name]; + [lines addObject:newLine(name, [NSString stringWithFormat:@"%f", cycle.totalTime / 1000000 / (double)cycle.count], [NSString stringWithFormat:@"%f", cycle.totalTime / 1000000.0], [NSString stringWithFormat:@"%llu", cycle.count], [NSString stringWithFormat:@"%f", cycle.totalSortTime / NS_PER_MS], [NSString stringWithFormat:@"%llu", cycle.sortCount])]; + } + [lines addObject:newLine(@"Total", _cycleCount > 0 ? [NSString stringWithFormat:@"%f", _totalCycleTime / 1000000 / (double)_cycleCount] : @"0", [NSString stringWithFormat:@"%f", _totalCycleTime / 1000000.0], [NSString stringWithFormat:@"%llu", _cycleCount], [NSString stringWithFormat:@"%f", _totalSortTime / NS_PER_MS], [NSString stringWithFormat:@"%llu", _sortCount])]; + + return [@"\n" stringByAppendingString:[lines componentsJoinedByString:@"\n"]]; +} + +- (NSString *)sortTimeStats { + if (![[[NSProcessInfo processInfo] arguments] containsObject:@"-graphProfileTime"]) { + return @"Use run argument '-graphProfileTime' to enable behavior graph time profiling."; + } + + NSMutableArray *lines = [NSMutableArray new]; + + NSString *(^newLine)(NSString *, NSString *, NSString *, NSString *) = ^NSString *(NSString *unsortedCount, NSString *averageTime, NSString *totalTime, NSString *count) { + NSMutableString *string = [NSMutableString new]; + for (int i = 0; i < 20 - (NSInteger)unsortedCount.length; ++i) { + [string appendString:@" "]; + } + [string appendString:unsortedCount]; + + for (int i = 0; i < 20 - (NSInteger)averageTime.length; ++i) { + [string appendString:@" "]; + } + [string appendString:averageTime]; + + for (int i = 0; i < 20 - (NSInteger)totalTime.length; ++i) { + [string appendString:@" "]; + } + [string appendString:totalTime]; + + for (int i = 0; i < 20 - (NSInteger)count.length; ++i) { + [string appendString:@" "]; + } + [string appendString:count]; + + return string; + }; + + [lines addObject:newLine(@"# Behaviors Sorted", @"Avg (ms)", @"Total (ms)", @"Count")]; + for (NSNumber *unsortedCount in [_sortStats.allKeys sortedArrayUsingComparator:^NSComparisonResult(NSNumber * _Nonnull obj1, NSNumber * _Nonnull obj2) { + NSTimeInterval time1 = ({ BGSortStats *stats = _sortStats[obj1]; stats.totalTime / (double)stats.count; }); + NSTimeInterval time2 = ({ BGSortStats *stats = _sortStats[obj2]; stats.totalTime / (double)stats.count; }); + if (time1 > time2) { + return NSOrderedAscending; + } else if (time1 < time2) { + return NSOrderedDescending; + } else { + return NSOrderedSame; + } + }]) { + BGSortStats *cycle = _sortStats[unsortedCount]; + [lines addObject:newLine([NSString stringWithFormat:@"%llu", unsortedCount.unsignedLongLongValue], [NSString stringWithFormat:@"%f", cycle.totalTime / NS_PER_MS / (double)cycle.count], [NSString stringWithFormat:@"%f", cycle.totalTime / NS_PER_MS], [NSString stringWithFormat:@"%llu", cycle.count])]; + } + [lines addObject:newLine(@"Total", _sortCount > 0 ? [NSString stringWithFormat:@"%f", _totalSortTime / NS_PER_MS / (double)_sortCount] : @"0", [NSString stringWithFormat:@"%f", _totalSortTime / NS_PER_MS], [NSString stringWithFormat:@"%llu", _sortCount])]; + + return [@"\n" stringByAppendingString:[lines componentsJoinedByString:@"\n"]]; +} + +@end + +#endif diff --git a/doc-site/examples/objc/BGExamples/ChatExtent.h b/doc-site/examples/objc/BGExamples/ChatExtent.h new file mode 100644 index 0000000..65ff10c --- /dev/null +++ b/doc-site/examples/objc/BGExamples/ChatExtent.h @@ -0,0 +1,33 @@ +// +// ChatExtent.h +// BGExamples +// +// Created by Sean Levin on 5/13/20. +// Copyright © 2020 Verizon Media. All rights reserved. +// + +#import "BGGraph.h" + +NS_ASSUME_NONNULL_BEGIN + +@class ParticipantExtent; + +// @tag::chat_extent[] +@class ChatExtent; +@interface ChatExtent : BGExtent +// @end::chat_extent[] + +@property (nonatomic, readonly) BGMoment *participantJoined; +@property (nonatomic, readonly) BGMoment *participantDisconnected; + +// @tag::chat_participants_resources[] +@property (nonatomic, readonly) BGState *participants; +// @end::chat_participants_resources[] +@property (nonatomic, readonly) BGState *pinnedParticipant; + +@property (nonatomic, readonly) BGResource *participantsRelink; +@property (nonatomic, readonly) BGBehavior *pinnedBehavior; + +@end + +NS_ASSUME_NONNULL_END diff --git a/doc-site/examples/objc/BGExamples/ChatExtent.m b/doc-site/examples/objc/BGExamples/ChatExtent.m new file mode 100644 index 0000000..e592be6 --- /dev/null +++ b/doc-site/examples/objc/BGExamples/ChatExtent.m @@ -0,0 +1,81 @@ +// +// ChatExtent.m +// BGExamples +// +// Created by Sean Levin on 5/13/20. +// Copyright © 2020 Verizon Media. All rights reserved. +// + +#import "ChatExtent.h" +#import "ParticipantExtent.h" + +@implementation ChatExtent + +- (instancetype)initWithGraph:(BGGraph *)graph { + self = [super initWithGraph:graph]; + if (self) { + + + // tag::participants[] + _participantJoined = [self moment]; + _participantDisconnected = [self moment]; + _participants = [self stateWithValue:[NSMutableDictionary new]]; + [self behaviorWithDemands:@[_participantJoined, _participantDisconnected] supplies:@[_participants] runBlock:^(ChatExtent * _Nonnull extent) { + + if (extent.participantJoined.justUpdated) { + NSString *participantId = extent.participantJoined.value; + ParticipantExtent *participant = [[ParticipantExtent alloc] initWithGraph:extent.graph participantId:participantId chat:extent]; + [participant addToGraph]; + extent.participants.value[participantId] = participant; + [extent.participants updateValueForce:extent.participants.value]; + } + + if (extent.participantDisconnected.justUpdated) { + NSString *participantId = extent.participantDisconnected.value; + ParticipantExtent *participant = extent.participants.value[participantId]; + [participant removeFromGraph]; + extent.participants.value[participantId] = nil; + [extent.participants updateValueForce:extent.participants.value]; + } + + }]; + // end::participants[] + + // tag::chat_relink_pinned[] + _participantsRelink = [self resource]; + [self behaviorWithDemands:@[_participants] supplies:@[_participantsRelink] runBlock:^(ChatExtent * _Nonnull extent) { + NSMutableArray *demands = [NSMutableArray new]; + [demands addObject:extent.participants]; + [demands addObject:extent.participantsRelink]; + for (ParticipantExtent *p in extent.participants.value) { + [demands addObject:p.pinTap]; + } + [extent.pinnedBehavior setDemands:demands]; + }]; + // end::chat_relink_pinned[] + + // tag::chat_pinned[] + _pinnedParticipant = [self stateWithValue:nil]; + _pinnedBehavior = [self behaviorWithDemands:@[_participants, _participantsRelink] supplies:@[_pinnedParticipant] runBlock:^(ChatExtent * _Nonnull extent) { + + ParticipantExtent *currentPinned = extent.pinnedParticipant.value; + ParticipantExtent *newPinned = nil; + for (ParticipantExtent *participant in extent.participants.value.allValues) { + if (participant.pinTap.justUpdated) { + newPinned = participant; + break; + } else if (participant == currentPinned) { + newPinned = currentPinned; + } + } + + [extent.pinnedParticipant updateValue:newPinned]; + + }]; + // end::chat_pinned[] + + } + return self; +} + +@end diff --git a/doc-site/examples/objc/BGExamples/ImperativeLoginPageViewController.h b/doc-site/examples/objc/BGExamples/ImperativeLoginPageViewController.h new file mode 100644 index 0000000..fb5d41a --- /dev/null +++ b/doc-site/examples/objc/BGExamples/ImperativeLoginPageViewController.h @@ -0,0 +1,22 @@ +// +// ImperativeLoginPageViewController.h +// BGExamples +// +// Created by Sean Levin on 3/18/20. +// Copyright © 2020 Verizon Media. All rights reserved. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface ImperativeLoginPageViewController : UIViewController + +@property (nonatomic) IBOutlet UITextField *emailField; +@property (nonatomic) IBOutlet UITextField *passwordField; +@property (nonatomic) IBOutlet UIButton *loginButton; + + +@end + +NS_ASSUME_NONNULL_END diff --git a/doc-site/examples/objc/BGExamples/ImperativeLoginPageViewController.m b/doc-site/examples/objc/BGExamples/ImperativeLoginPageViewController.m new file mode 100644 index 0000000..91cbd86 --- /dev/null +++ b/doc-site/examples/objc/BGExamples/ImperativeLoginPageViewController.m @@ -0,0 +1,41 @@ +// +// ImperativeLoginPageViewController.m +// BGExamples +// +// Created by Sean Levin on 3/18/20. +// Copyright © 2020 Verizon Media. All rights reserved. +// + +#import "ImperativeLoginPageViewController.h" + +@interface ImperativeLoginPageViewController () + +@end + +@implementation ImperativeLoginPageViewController + +- (BOOL)validEmailAddress:(NSString *)email { + return email.length > 0 && [email containsString:@"@"]; +} + +- (void)viewDidLoad { + [super viewDidLoad]; + // Do any additional setup after loading the view. +} + +- (IBAction)didUpdateEmailField:(id)sender { + [self checkEnableLoginButton]; +} + +- (IBAction)didUpdatePasswordField:(id)sender { + [self checkEnableLoginButton]; +} + +- (void)checkEnableLoginButton { + NSString *email = self.emailField.text; + NSString *password = self.passwordField.text; + BOOL hasPassword = password.length > 0; + self.loginButton.enabled = [self validEmailAddress:email] && hasPassword; +} + +@end diff --git a/doc-site/examples/objc/BGExamples/Info.plist b/doc-site/examples/objc/BGExamples/Info.plist new file mode 100644 index 0000000..7b6037c --- /dev/null +++ b/doc-site/examples/objc/BGExamples/Info.plist @@ -0,0 +1,64 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + $(PRODUCT_BUNDLE_PACKAGE_TYPE) + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + LSRequiresIPhoneOS + + UIApplicationSceneManifest + + UIApplicationSupportsMultipleScenes + + UISceneConfigurations + + UIWindowSceneSessionRoleApplication + + + UISceneConfigurationName + Default Configuration + UISceneDelegateClassName + SceneDelegate + UISceneStoryboardFile + Main + + + + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + diff --git a/doc-site/examples/objc/BGExamples/LoginExtent.h b/doc-site/examples/objc/BGExamples/LoginExtent.h new file mode 100644 index 0000000..4b1dded --- /dev/null +++ b/doc-site/examples/objc/BGExamples/LoginExtent.h @@ -0,0 +1,31 @@ +// +// LoginExtent.h +// BGExamples +// +// Created by Sean Levin on 3/18/20. +// Copyright © 2020 Verizon Media. All rights reserved. +// + +#import "BGGraph.h" +#import "LoginPageViewController.h" + +NS_ASSUME_NONNULL_BEGIN + +// tag::login_enable_extent[] +@class LoginExtent; +@interface LoginExtent : BGExtent +@property (nonatomic, readonly) BGState *email; +@property (nonatomic, readonly) BGState *password; +// end::login_enable_extent[] + +@property (nonatomic, readonly) BGMoment *loginClick; +@property (nonatomic, readonly) BGMoment *returnKey; +@property (nonatomic, readonly) BGState *emailValid; +@property (nonatomic, readonly) BGState *passwordValid; +@property (nonatomic, readonly) BGState *loginEnabled; +@property (nonatomic, readonly) BGState *loggingIn; +@property (nonatomic, readonly) BGMoment *loginComplete; +@property (nonatomic, readwrite, weak) LoginPageViewController *login; +@end + +NS_ASSUME_NONNULL_END diff --git a/doc-site/examples/objc/BGExamples/LoginExtent.m b/doc-site/examples/objc/BGExamples/LoginExtent.m new file mode 100644 index 0000000..ec0d84e --- /dev/null +++ b/doc-site/examples/objc/BGExamples/LoginExtent.m @@ -0,0 +1,244 @@ +// +// LoginExtent.m +// BGExamples +// +// Created by Sean Levin on 3/18/20. +// Copyright © 2020 Verizon Media. All rights reserved. +// + +#import "LoginExtent.h" + +@implementation LoginExtent + +/* +- (instancetype)init { + self = [super init]; + if (self) { + + + } + return self; +} +*/ + // tag::login_enable_init[] +- (instancetype)initWithGraph:(BGGraph *)graph { + self = [super initWithGraph:graph]; + + _email = [self stateWithValue:@""]; + _password = [self stateWithValue:@""]; + + // tag::login_enable_behavior[] + [self behaviorWithDemands:@[self.email, self.password] + supplies:nil + runBlock:^(LoginExtent * _Nonnull extent) { + // end::login_enable_init[] + + NSString *email = extent.email.value; + NSString *password = extent.password.value; + BOOL hasPassword = password.length > 0; + BOOL loginEnabled = [extent validEmailAddress:email] && hasPassword; + [extent sideEffect:@"enable login button" runBlock:^(LoginExtent * _Nonnull extent) { + extent.login.loginButton.enabled = loginEnabled; + }]; + + }]; + // end::login_enable_behavior[] + + return self; +} + +- (void)initBehaviorGraphComplete { + + _loggingIn = [self stateWithValue:@NO]; + + // tag::login_complete_email[] + _emailValid = [self stateWithValue:@NO]; + [self behaviorWithDemands:@[self.email] + supplies:@[self.emailValid] + runBlock:^(LoginExtent * _Nonnull extent) { + + NSString *email = extent.email.value; + BOOL emailValid = [self validEmailAddress:email]; + [extent.emailValid updateValue:@(emailValid)]; + + }]; + // end::login_complete_email[] + + _passwordValid = [self stateWithValue:@NO]; + [self behaviorWithDemands:@[self.password] + supplies:@[self.passwordValid] + runBlock:^(LoginExtent * _Nonnull extent) { + + NSString *password = extent.password.value; + BOOL passwordValid = password.length > 0; + [extent.passwordValid updateValue:@(passwordValid)]; + + }]; + + + // tag::login_complete_enable[] + _loginEnabled = [self stateWithValue:@NO]; + [self behaviorWithDemands:@[self.emailValid, self.passwordValid, self.loggingIn] + supplies:@[self.loginEnabled] + runBlock:^(LoginExtent * _Nonnull extent) { + + BOOL enabled = (extent.emailValid.value.boolValue && + extent.passwordValid.value.boolValue && + !extent.loggingIn.value.boolValue); + [extent.loginEnabled updateValue:@(enabled)]; + [extent sideEffect:@"enable login button" runBlock:^(LoginExtent * _Nonnull extent) { + extent.login.loginButton.enabled = extent.loginEnabled.value.boolValue; + }]; + + }]; + // end::login_complete_enable[] + + // tag::login_complete_login[] + _loginClick = [self moment]; + _returnKey = [self moment]; + _loginComplete = [self moment]; + [self behaviorWithDemands:@[self.loginClick, self.returnKey, self.loginComplete] + supplies:@[self.loggingIn] + runBlock:^(LoginExtent * _Nonnull extent) { + + if ((extent.loginClick.justUpdated || extent.returnKey.justUpdated) && + extent.loginEnabled.traceValue.boolValue) { + // Start login + [extent.loggingIn updateValue:@YES]; + } else if (extent.loginComplete.justUpdated && + extent.loggingIn.value.boolValue) { + // Complete login + [extent.loggingIn updateValue:@NO]; + } + + if ([extent.loggingIn justUpdatedTo:@YES]) { + [extent sideEffect:@"login api call" runBlock:^(LoginExtent * _Nonnull extent) { + [extent login:extent.email.value password:extent.password.value complete:^(BOOL success) { + [extent action:@"login complete" runBlock:^{ + [extent.loginComplete updateValue:@(success)]; + }]; + }]; + }]; + } + + }]; + // end::login_complete_login[] + + /* + // Dont delete; its used in the documentation + // this has an example of requireSync + + [self behaviorWithDemands:@[self.loginClick, self.returnKey, self.loginComplete] + supplies:@[self.loggingIn] + runBlock:^(LoginExtent t* _Nonnull extent) { + + if ((extent.loginClick.justHappened || extent.returnKey.justHappened) && + extent.loginEnabled.traceValue.boolValue) { + // Start login + [extent.loggingIn updateValue:@YES]; + } else if (extent.loginComplete.justHappened && + extent.loggingIn.value.boolValue) { + // Complete login + [extent.loggingIn updateValue:@NO]; + } + + if ([extent.loggingIn justChangedTo:@YES]) { + // tag::login_complete_loginalt[] + [extent sideEffect:@"login api call" block:^(LoginExtent * _Nonnull extent) { + [extent login:extent.email.value password:extent.password.value complete:^(BOOL success) { + [extent.graph action:@"login complete" requireSync:NO runBlock:^{ + [extent.loginComplete happen:@(success)]; + }]; + }]; + }]; + // end::login_complete_loginalt[] + } + + }]; + */ +} + +- (instancetype)initShortWithGraph:(BGGraph *)graph { + // tag::login_intro_short1[] + [self behaviorWithDemands:@[self.email, self.password] + supplies:@[self.loginEnabled] + runBlock:^(LoginExtent *extent) { + + BOOL emailValid = [extent validEmailAddress:extent.email.value]; + BOOL passwordValid = extent.password.value.length > 0; + BOOL enabled = emailValid && passwordValid; + [extent.loginEnabled updateValue:@(enabled)]; + + }]; + // end::login_intro_short1[] + + // tag::login_intro_short2[] + [self behaviorWithDemands:@[self.loginClick] + supplies:@[self.loggingIn] + runBlock:^(LoginExtent * _Nonnull extent) { + if (extent.loginClick.justUpdated && !extent.loggingIn.value.boolValue) { + [extent.loggingIn updateValue:@YES]; + } + }]; + + [self behaviorWithDemands:@[self.email, self.password, self.loggingIn] + supplies:@[self.loginEnabled] + runBlock:^(LoginExtent *extent) { + + BOOL emailValid = [extent validEmailAddress:extent.email.value]; + BOOL passwordValid = extent.password.value.length > 0; + BOOL enabled = emailValid && passwordValid && !self.loggingIn.value.boolValue; + [extent.loginEnabled updateValue:@(enabled)]; + + }]; + // end::login_intro_short2[] + + + // tag::login_intro_sideeffect[] + [self behaviorWithDemands:@[self.email, self.password, self.loggingIn] + supplies:@[self.loginEnabled] + runBlock:^(LoginExtent *extent) { + + BOOL emailValid = [extent validEmailAddress:extent.email.value]; + BOOL passwordValid = extent.password.value.length > 0; + BOOL enabled = emailValid && passwordValid && !self.loggingIn.value.boolValue; + [extent.loginEnabled updateValue:@(enabled)]; + + [extent sideEffect:@"enable login button" runBlock:^(LoginExtent * _Nonnull extent) { + extent.loginButton.enabled = extent.loginEnabled.value.boolValue; + }]; + }]; + // end::login_intro_sideeffect[] + + return self; +} + +// tag::login_intro_action[] +- (void)loginButtonClicked:(id)sender { + [self.graph action:@"loginButtonClicked" runBlock:^{ + [self.loginClick update]; + }]; +} +// end::login_intro_action[] + +- (BOOL)validEmailAddress:(NSString *)email { + return email.length > 0 && [email containsString:@"@"]; +} + +- (void)login:(NSString *)email password:(NSString *)password complete:(void(^)(BOOL success))complete { + // some login api +} + +// tag::login_sequence_compare[] +- (BOOL)emailChangedSincePassword { + return self.email.event.sequence > self.password.event.sequence; +} +// end::login_sequence_compare[] + +// tag::login_timestamp[] +- (NSDate *)loginCompletedWhen { + return self.loginComplete.event.timestamp; +} +// end::login_timestamp[] + +@end diff --git a/doc-site/examples/objc/BGExamples/LoginPageViewController.h b/doc-site/examples/objc/BGExamples/LoginPageViewController.h new file mode 100644 index 0000000..e67ecc3 --- /dev/null +++ b/doc-site/examples/objc/BGExamples/LoginPageViewController.h @@ -0,0 +1,23 @@ +// +// LoginPageViewController.h +// BGExamples +// +// Created by Sean Levin on 3/18/20. +// Copyright © 2020 Verizon Media. All rights reserved. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface LoginPageViewController : UIViewController + +@property (nonatomic) IBOutlet UITextField *emailField; +@property (nonatomic) IBOutlet UITextField *passwordField; +@property (nonatomic) IBOutlet UIButton *loginButton; + +@property (nonatomic) IBOutlet UILabel *emailFeedback; +@property (nonatomic) IBOutlet UILabel *passwordFeedback; +@end + +NS_ASSUME_NONNULL_END diff --git a/doc-site/examples/objc/BGExamples/LoginPageViewController.m b/doc-site/examples/objc/BGExamples/LoginPageViewController.m new file mode 100644 index 0000000..59bed9d --- /dev/null +++ b/doc-site/examples/objc/BGExamples/LoginPageViewController.m @@ -0,0 +1,62 @@ +// +// LoginPageViewController.m +// BGExamples +// +// Created by Sean Levin on 3/18/20. +// Copyright © 2020 Verizon Media. All rights reserved. +// + +#import "LoginPageViewController.h" +#import "BGGraph.h" +#import "LoginExtent.h" + +@interface LoginPageViewController () +@property (nonatomic) BGGraph *graph; +@property (nonatomic) LoginExtent *loginExtent; + +@end + +@implementation LoginPageViewController + +- (instancetype)initWithCoder:(NSCoder *)coder { + self = [super initWithCoder:coder]; + if (self) { + // tag::login_enable_setup[] + _graph = [[BGGraph alloc] init]; + _loginExtent = [[LoginExtent alloc] initWithGraph:_graph]; + [_graph action:@"new login page" runBlock:^{ + [self.loginExtent addToGraph]; + }]; + // end::login_enable_setup[] + } + return self; +} + +- (void)viewDidLoad { + [super viewDidLoad]; + // Do any additional setup after loading the view. +} + +// tag::login_enable_actions[] +- (IBAction)didUpdateEmailField:(id)sender { + [self.graph action:@"update email" runBlock:^{ + [self.loginExtent.email updateValue:self.emailField.text]; + }]; +} + +- (IBAction)didUpdatePasswordField:(id)sender { + [self.graph action:@"update password" runBlock:^{ + [self.loginExtent.password updateValue:self.passwordField.text]; + }]; +} +// end::login_enable_actions[] + +// tag::login_complete_click[] +- (IBAction)loginButtonClicked:(id)sender { + [self.graph action:@"login button" runBlock:^{ + [self.loginExtent.loginClick update]; + }]; +} +// end::login_complete_click[] + +@end diff --git a/doc-site/examples/objc/BGExamples/ParticipantExtent.h b/doc-site/examples/objc/BGExamples/ParticipantExtent.h new file mode 100644 index 0000000..c3cfb87 --- /dev/null +++ b/doc-site/examples/objc/BGExamples/ParticipantExtent.h @@ -0,0 +1,38 @@ +// +// ParticipantExtent.h +// BGExamples +// +// Created by Sean Levin on 5/13/20. +// Copyright © 2020 Verizon Media. All rights reserved. +// + +#import "BGGraph.h" + +NS_ASSUME_NONNULL_BEGIN + +@class ChatExtent; + +// @tag::participant_extent[] +@class ParticipantExtent; +@interface ParticipantExtent : BGExtent +// @end::participant_extent[] + +@property (nonatomic, weak, readonly) ChatExtent *chatExtent; +// @tag::participant_mute_resources[] +@property (nonatomic, readonly) BGMoment *muteTap; +@property (nonatomic, readonly) BGState *muted; +// @end::participant_mute_resources[] + +// @tag::participant_pin_resources[] +@property (nonatomic, readonly) BGMoment *pinTap; +// @end::participant_pin_resources[] + +@property (nonatomic) BGBehavior *muteBehavior; + +@property (nonatomic, readonly) NSString *participantId; + +- (instancetype)initWithGraph:(BGGraph *)graph participantId:(NSString *)participantId chat:(ChatExtent *)chatExtent; + +@end + +NS_ASSUME_NONNULL_END diff --git a/doc-site/examples/objc/BGExamples/ParticipantExtent.m b/doc-site/examples/objc/BGExamples/ParticipantExtent.m new file mode 100644 index 0000000..f6f498c --- /dev/null +++ b/doc-site/examples/objc/BGExamples/ParticipantExtent.m @@ -0,0 +1,79 @@ +// +// ParticipantExtent.m +// BGExamples +// +// Created by Sean Levin on 5/13/20. +// Copyright © 2020 Verizon Media. All rights reserved. +// + +#import "ParticipantExtent.h" +#import "ChatExtent.h" + +@implementation ParticipantExtent + +- (instancetype)initWithGraph:(BGGraph *)graph participantId:(NSString *)participantId chat:(ChatExtent *)chatExtent { + self = [super initWithGraph:graph]; + if (self) { + + _chatExtent = chatExtent; + _participantId = participantId; + + // tag::participant_mute[] + _muteTap = [self moment]; + _muted = [self stateWithValue:@NO]; + [self behaviorWithDemands:@[_muteTap] supplies:@[_muted] runBlock:^(ParticipantExtent * _Nonnull extent) { + if (extent.muteTap.justUpdated) { + [extent.muted updateValue:@(!extent.muted.value.boolValue)]; + if (extent.muted.justUpdated) { + [extent sideEffect:@"mute toggle" runBlock:^(ParticipantExtent * _Nonnull extent) { + [extent muteParticipant:extent.muted.value.boolValue]; + [extent updateMuteUI:extent.muted.value.boolValue]; + }]; + } + } + }]; + // end::participant_mute[] + + _pinTap = [self moment]; + // tag::participant_pinned[] + [self behaviorWithDemands:@[_chatExtent.pinnedParticipant] supplies:nil runBlock:^(ParticipantExtent * _Nonnull extent) { + + if ([extent.chatExtent.pinnedParticipant justUpdatedTo:extent]) { + [extent sideEffect:@"show as pinned" runBlock:^(ParticipantExtent * _Nonnull extent) { + [extent updatePinUI:YES]; + }]; + } else if ([extent.chatExtent.pinnedParticipant justUpdatedFrom:extent]) { + [extent sideEffect:@"show as normal" runBlock:^(ParticipantExtent * _Nonnull extent) { + [extent updatePinUI:NO]; + }]; + } + }]; + // end::participant_pinned[] + + } + return self; +} + +- (void)alts { + // tag::participant_mute_alt[] + _muteBehavior = [self behaviorWithDemands:@[_muteTap] supplies:@[_muted] //... + // end::participant_mute_alt[] + runBlock:^(ParticipantExtent * _Nonnull extent) { + + }]; + +} + +- (void)updatePinUI:(BOOL)pinned { + +} + +- (void)updateMuteUI:(BOOL)mute { + // update ui +} + +- (void)muteParticipant:(BOOL)mute { + // external api call +} + +@end diff --git a/doc-site/examples/objc/BGExamples/SceneDelegate.h b/doc-site/examples/objc/BGExamples/SceneDelegate.h new file mode 100644 index 0000000..fe7e723 --- /dev/null +++ b/doc-site/examples/objc/BGExamples/SceneDelegate.h @@ -0,0 +1,16 @@ +// +// SceneDelegate.h +// BGExamples +// +// Created by Sean Levin on 3/6/20. +// Copyright © 2020 Verizon Media. All rights reserved. +// + +#import + +@interface SceneDelegate : UIResponder + +@property (strong, nonatomic) UIWindow * window; + +@end + diff --git a/doc-site/examples/objc/BGExamples/SceneDelegate.m b/doc-site/examples/objc/BGExamples/SceneDelegate.m new file mode 100644 index 0000000..d6698dd --- /dev/null +++ b/doc-site/examples/objc/BGExamples/SceneDelegate.m @@ -0,0 +1,50 @@ +#import "SceneDelegate.h" + +@interface SceneDelegate () + +@end + +@implementation SceneDelegate + + +- (void)scene:(UIScene *)scene willConnectToSession:(UISceneSession *)session options:(UISceneConnectionOptions *)connectionOptions { + // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`. + // If using a storyboard, the `window` property will automatically be initialized and attached to the scene. + // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead). +} + + +- (void)sceneDidDisconnect:(UIScene *)scene { + // Called as the scene is being released by the system. + // This occurs shortly after the scene enters the background, or when its session is discarded. + // Release any resources associated with this scene that can be re-created the next time the scene connects. + // The scene may re-connect later, as its session was not neccessarily discarded (see `application:didDiscardSceneSessions` instead). +} + + +- (void)sceneDidBecomeActive:(UIScene *)scene { + // Called when the scene has moved from an inactive state to an active state. + // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive. +} + + +- (void)sceneWillResignActive:(UIScene *)scene { + // Called when the scene will move from an active state to an inactive state. + // This may occur due to temporary interruptions (ex. an incoming phone call). +} + + +- (void)sceneWillEnterForeground:(UIScene *)scene { + // Called as the scene transitions from the background to the foreground. + // Use this method to undo the changes made on entering the background. +} + + +- (void)sceneDidEnterBackground:(UIScene *)scene { + // Called as the scene transitions from the foreground to the background. + // Use this method to save data, release shared resources, and store enough scene-specific state information + // to restore the scene back to its current state. +} + + +@end diff --git a/doc-site/examples/objc/BGExamples/SigngupPageViewController.h b/doc-site/examples/objc/BGExamples/SigngupPageViewController.h new file mode 100644 index 0000000..dba437c --- /dev/null +++ b/doc-site/examples/objc/BGExamples/SigngupPageViewController.h @@ -0,0 +1,27 @@ +// +// SigngupPageViewController.h +// BGExamples +// +// Created by Sean Levin on 3/6/20. +// Copyright © 2020 Verizon Media. All rights reserved. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface SigngupPageViewController : UIViewController + +@property (nonatomic) IBOutlet UILabel *usernameErrorLabel; +@property (nonatomic) IBOutlet UITextField *usernameTextField; +@property (nonatomic) IBOutlet UILabel *passwordErrorLabel; +@property (nonatomic) IBOutlet UITextField *password1Field; +@property (nonatomic) IBOutlet UITextField *password2Field; +@property (nonatomic) IBOutlet UIButton *signupButton; + + +- (void)startSignupWithUsername:(NSString *)username password:(NSString *)password; + +@end + +NS_ASSUME_NONNULL_END diff --git a/doc-site/examples/objc/BGExamples/SigngupPageViewController.m b/doc-site/examples/objc/BGExamples/SigngupPageViewController.m new file mode 100644 index 0000000..983bed5 --- /dev/null +++ b/doc-site/examples/objc/BGExamples/SigngupPageViewController.m @@ -0,0 +1,57 @@ +// +// SigngupPageViewController.m +// BGExamples +// +// Created by Sean Levin on 3/6/20. +// Copyright © 2020 Verizon Media. All rights reserved. +// + +#import "SigngupPageViewController.h" +#import "BGGraph.h" +#import "SignupExtent.h" + +@interface SigngupPageViewController () +@property (nonatomic) BGGraph *graph; +@property (nonatomic) SignupExtent *signupExtent; +@end + +@implementation SigngupPageViewController + +- (void)viewDidLoad { + [super viewDidLoad]; + + _graph = [[BGGraph alloc] init]; + _signupExtent = [[SignupExtent alloc] initWithGraph:_graph]; + _signupExtent.signup = self; + [_graph action:@"initial setup" runBlock:^{ + [self.signupExtent addToGraph]; + }]; +} + +- (void)startSignupWithUsername:(NSString *)username password:(NSString *)password { + NSLog(@"Signup api call sent."); +} + +- (IBAction)didTapSubmitButton:(id)sender { + [self.graph action:_fname runBlock:^{ + [self.signupExtent.signupButtonClicked update]; + }]; +} + +- (IBAction)didUpdateUsernameField:(id)sender { + [self.graph action:_fname runBlock:^{ + [self.signupExtent.username updateValue:self.usernameTextField.text]; + }]; +} + +- (IBAction)didUpdatePasswordField:(id)sender { + [self.graph action:_fname runBlock:^{ + if (sender == self.password1Field) { + [self.signupExtent.password1 updateValue:self.password1Field.text]; + } else if (sender == self.password2Field) { + [self.signupExtent.password2 updateValue:self.password2Field.text]; + } + }]; +} + +@end diff --git a/doc-site/examples/objc/BGExamples/SignupExtent.h b/doc-site/examples/objc/BGExamples/SignupExtent.h new file mode 100644 index 0000000..570c3c5 --- /dev/null +++ b/doc-site/examples/objc/BGExamples/SignupExtent.h @@ -0,0 +1,31 @@ +// +// SignupExtent.h +// BGExamples +// +// Created by Sean Levin on 3/6/20. +// Copyright © 2020 Verizon Media. All rights reserved. +// + +#import "BGGraph.h" +#import "SigngupPageViewController.h" + +NS_ASSUME_NONNULL_BEGIN + +@class SignupExtent; +@interface SignupExtent : BGExtent + +@property (nonatomic, readonly) BGState *username; +@property (nonatomic, readonly) BGState *password1; +@property (nonatomic, readonly) BGState *password2; +@property (nonatomic, readonly) BGMoment *signupButtonClicked; + +@property (nonatomic, readonly) BGState *usernameValid; +@property (nonatomic, readonly) BGState *passwordsValid; +@property (nonatomic, readonly) BGState *signupEnabled; +@property (nonatomic, readonly) BGState *signingUp; + +@property (nonatomic, readwrite, weak) SigngupPageViewController *signup; + +@end + +NS_ASSUME_NONNULL_END diff --git a/doc-site/examples/objc/BGExamples/SignupExtent.m b/doc-site/examples/objc/BGExamples/SignupExtent.m new file mode 100644 index 0000000..f695320 --- /dev/null +++ b/doc-site/examples/objc/BGExamples/SignupExtent.m @@ -0,0 +1,99 @@ +// +// SignupExtent.m +// BGExamples +// +// Created by Sean Levin on 3/6/20. +// Copyright © 2020 Verizon Media. All rights reserved. +// + +#import "SignupExtent.h" + +@implementation SignupExtent + +- (instancetype)initWithGraph:(BGGraph *)graph { + self = [super initWithGraph:graph]; + if (self) { + + _username = [self stateWithValue:nil]; + _password1 = [self stateWithValue:nil]; + _password2 = [self stateWithValue:nil]; + _signupButtonClicked = [self moment]; + + _usernameValid = [self stateWithValue:@NO]; + _passwordsValid = [self stateWithValue:@NO]; + _signupEnabled = [self stateWithValue:@NO]; + _signingUp = [self stateWithValue:@NO]; + + + [self behaviorWithDemands:@[self.username] supplies:@[self.usernameValid] runBlock:^(SignupExtent * _Nonnull extent) { + + // Validate username and offer feedback + NSString *username = extent.username.value; + BOOL valid = [username length] >= 10 && ![username containsString:@" "]; + [extent.usernameValid updateValue:@(valid)]; + [extent sideEffect:@"update username error message" runBlock:^(SignupExtent * _Nonnull extent) { + if (extent.usernameValid.value.boolValue) { + extent.signup.usernameErrorLabel.hidden = YES; + } else { + extent.signup.usernameErrorLabel.hidden = NO; + extent.signup.usernameErrorLabel.text = @"Username must be at least 10 characters and contain no empty spaces."; + [extent.signup.usernameErrorLabel sizeToFit]; + + } + }]; + + }]; + + + [self behaviorWithDemands:@[self.password1, self.password2] supplies:@[self.passwordsValid] runBlock:^(SignupExtent * _Nonnull extent) { + + // Validate passwords and offer feedback + NSString *password1 = extent.password1.value; + NSString *password2 = extent.password2.value; + BOOL valid = [password1 length] >= 10 && [password1 isEqualToString:password2]; + [extent.passwordsValid updateValue:@(valid)]; + [extent sideEffect:@"update password valid error message" runBlock:^(SignupExtent * _Nonnull extent) { + if (extent.passwordsValid.value.boolValue) { + extent.signup.passwordErrorLabel.hidden = YES; + } else { + extent.signup.passwordErrorLabel.hidden = NO; + extent.signup.passwordErrorLabel.text = @"Passwords must match and be at least 10 characters long."; + [extent.signup.passwordErrorLabel sizeToFit]; + } + }]; + + }]; + + + [self behaviorWithDemands:@[self.usernameValid, self.passwordsValid, self.signingUp] supplies:@[self.signupEnabled] runBlock:^(SignupExtent * _Nonnull extent) { + + // Signup only allowed when username and password fields are valid + [extent.signupEnabled updateValue:@(extent.usernameValid.value.boolValue && extent.passwordsValid.value.boolValue && !extent.signingUp.value.boolValue)]; + [extent sideEffect:@"enable signup button" runBlock:^(SignupExtent * _Nonnull extent) { + extent.signup.signupButton.enabled = extent.signupEnabled.value.boolValue; + }]; + + }]; + + + [self behaviorWithDemands:@[self.signupButtonClicked] supplies:@[self.signingUp] runBlock:^(SignupExtent * _Nonnull extent) { + + // On signup switch to signing up mode which will disable more user interaction + // Note signupEnabled uses trace value to prevent graph cycle with signupEnabled behavior + if (extent.signupButtonClicked.justUpdated && extent.signupEnabled.traceValue.boolValue) { + [extent.signingUp updateValue:@YES]; + [extent sideEffect:@"submit signup form" runBlock:^(SignupExtent * _Nonnull extent) { + [extent.signup startSignupWithUsername:extent.username.value password:extent.password1.value]; + extent.signup.usernameTextField.enabled = !extent.signingUp.value.boolValue; + extent.signup.password1Field.enabled = !extent.signingUp.value.boolValue; + extent.signup.password2Field.enabled = !extent.signingUp.value.boolValue; + }]; + } + + }]; + } + return self; +} + + +@end diff --git a/doc-site/examples/objc/BGExamples/ViewController.h b/doc-site/examples/objc/BGExamples/ViewController.h new file mode 100644 index 0000000..cf8093b --- /dev/null +++ b/doc-site/examples/objc/BGExamples/ViewController.h @@ -0,0 +1,15 @@ +// +// ViewController.h +// BGExamples +// +// Created by Sean Levin on 3/6/20. +// Copyright © 2020 Verizon Media. All rights reserved. +// + +#import + +@interface ViewController : UIViewController + + +@end + diff --git a/doc-site/examples/objc/BGExamples/ViewController.m b/doc-site/examples/objc/BGExamples/ViewController.m new file mode 100644 index 0000000..e54e8f9 --- /dev/null +++ b/doc-site/examples/objc/BGExamples/ViewController.m @@ -0,0 +1,23 @@ +// +// ViewController.m +// BGExamples +// +// Created by Sean Levin on 3/6/20. +// Copyright © 2020 Verizon Media. All rights reserved. +// + +#import "ViewController.h" + +@interface ViewController () + +@end + +@implementation ViewController + +- (void)viewDidLoad { + [super viewDidLoad]; + // Do any additional setup after loading the view. +} + + +@end diff --git a/doc-site/examples/objc/BGExamples/main.m b/doc-site/examples/objc/BGExamples/main.m new file mode 100644 index 0000000..ace61c4 --- /dev/null +++ b/doc-site/examples/objc/BGExamples/main.m @@ -0,0 +1,19 @@ +// +// main.m +// BGExamples +// +// Created by Sean Levin on 3/6/20. +// Copyright © 2020 Verizon Media. All rights reserved. +// + +#import +#import "AppDelegate.h" + +int main(int argc, char * argv[]) { + NSString * appDelegateClassName; + @autoreleasepool { + // Setup code that might create autoreleased objects goes here. + appDelegateClassName = NSStringFromClass([AppDelegate class]); + } + return UIApplicationMain(argc, argv, nil, appDelegateClassName); +} diff --git a/doc-site/examples/objc/BGExamplesTests/BGExamplesTests.m b/doc-site/examples/objc/BGExamplesTests/BGExamplesTests.m new file mode 100644 index 0000000..89df1af --- /dev/null +++ b/doc-site/examples/objc/BGExamplesTests/BGExamplesTests.m @@ -0,0 +1,37 @@ +// +// BGExamplesTests.m +// BGExamplesTests +// +// Created by Sean Levin on 3/6/20. +// Copyright © 2020 Verizon Media. All rights reserved. +// + +#import + +@interface BGExamplesTests : XCTestCase + +@end + +@implementation BGExamplesTests + +- (void)setUp { + // Put setup code here. This method is called before the invocation of each test method in the class. +} + +- (void)tearDown { + // Put teardown code here. This method is called after the invocation of each test method in the class. +} + +- (void)testExample { + // This is an example of a functional test case. + // Use XCTAssert and related functions to verify your tests produce the correct results. +} + +- (void)testPerformanceExample { + // This is an example of a performance test case. + [self measureBlock:^{ + // Put the code you want to measure the time of here. + }]; +} + +@end diff --git a/doc-site/examples/objc/BGExamplesTests/Info.plist b/doc-site/examples/objc/BGExamplesTests/Info.plist new file mode 100644 index 0000000..64d65ca --- /dev/null +++ b/doc-site/examples/objc/BGExamplesTests/Info.plist @@ -0,0 +1,22 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + $(PRODUCT_BUNDLE_PACKAGE_TYPE) + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + + diff --git a/doc-site/examples/typescript/BGExamples/ChatExample.ts b/doc-site/examples/typescript/BGExamples/ChatExample.ts new file mode 100644 index 0000000..6b5ec38 --- /dev/null +++ b/doc-site/examples/typescript/BGExamples/ChatExample.ts @@ -0,0 +1,158 @@ +import { Graph, InitialEvent, ValuePersistence } from './behaveg/behavegjs'; +import { Behavior } from "./behaveg/behavior" +import { State, Moment, Resource } from "./behaveg/resource" +import { Extent } from "./behaveg/extent" + +// @tag::chat_extent[] +class ChatExtent extends Extent { +// @end::chat_extent[] + + participantJoined: Moment; + participantDisconnected: Moment; + + // @tag::chat_participants_resources[] + participants: State>; + // @end::chat_participants_resources[] + + pinnedParticipant: State; + + participantsRelink: Resource; + pinnedBehavior: Behavior; + + constructor(graph: Graph) { + super(graph); + + // tag::participants[] + this.participantJoined = new Moment(this); + this.participantDisconnected = new Moment(this); + this.participants = new State(new Map(), this); + this.makeBehavior([this.participantJoined, this.participantDisconnected], [this.participants], (extent : this) => { + if (extent.participantJoined.justUpdated) { + const participantId = extent.participantJoined.value; + const participant = new ParticipantExtent(extent.graph, participantId, extent); + participant.addToGraph(); + extent.participants.value.set(participantId, participant); + extent.participants.update(extent.participants.value, false); + } + + if (extent.participantDisconnected.justUpdated) { + const participantId = extent.participantDisconnected.value; + const participant = extent.participants.value.get(participantId); + participant.removeFromGraph(); + extent.participants.value.delete(participantId); + extent.participants.update(extent.participants.value, false); + + } + + }); + // end::participants[] + + // tag::chat_relink_pinned[] + this.participantsRelink = new Resource(this); + this.makeBehavior([this.participants], [this.participantsRelink], (extent: this) => { + let demands = []; + demands.push(extent.participants); + demands.push(extent.participantsRelink); + for (let participant of extent.participants.value.values()) { + demands.push(participant.pinTap); + } + extent.pinnedParticipant.suppliedBy.setDemands(demands); + }); + // end::chat_relink_pinned[] + + // tag::chat_pinned[] + this.pinnedParticipant = new State(null, this); + this.makeBehavior([this.participants, this.participantsRelink], [this.pinnedParticipant], (extent: this) => { + const currentPinned = extent.pinnedParticipant.value; + let newPinned: ParticipantExtent = null; + for (let participant of extent.participants.value.values()) { + if (participant.pinTap.justUpdated) { + newPinned = participant; + break; + } else if (participant === currentPinned) { + newPinned = currentPinned; + } + } + + extent.pinnedParticipant.update(newPinned, true); + }); + // end::chat_pinned[] + + + } +} + +// @tag::participant_extent[] +class ParticipantExtent extends Extent { +// @end::participant_extent[] + + chatExtent: ChatExtent; + // @tag::participant_mute_resources[] + muteTap: Moment; + muted: State; + // @end::participant_mute_resources[] + + // @tag::participant_pin_resources[] + pinTap: Moment; + // @end::participant_pin_resources[] + + muteBehavior: Behavior; + participantId: string; + + constructor(graph: Graph, participantId: string, chatExtent: ChatExtent) { + super(graph); + + this.chatExtent = chatExtent; + this.participantId = participantId; + this.pinTap = new Moment(this); + + // tag::participant_mute[] + this.muteTap = new Moment(this); + this.muted = new State(false, this); + this.makeBehavior([this.muteTap], [this.muted], (extent: this) => { + if (extent.muteTap.justUpdated) { + extent.muted.update(!extent.muted.value, true); + if (extent.muted.justUpdated) { + extent.sideEffect('mute toggle', (extent: this) => { + extent.muteParticipant(extent.muted.value); + extent.updateMuteUI(extent.muted.value); + }); + } + } + }); + // end::participant_mute[] + + /* + // tag::participant_mute_alt[] + this.muteBehavior = this.makeBehavior([this.muteTap], [this.muted], //... + // end::participant_mute_alt[] + */ + + // tag::participant_pinned[] + this.makeBehavior([this.chatExtent.pinnedParticipant], null, (extent: this) => { + if (extent.chatExtent.pinnedParticipant.justUpdatedTo(extent)) { + extent.sideEffect('show as pinned', (extent: this) => { + extent.updatePinUI(true); + }); + } else if (extent.chatExtent.pinnedParticipant.justUpdatedFrom(extent)) { + extent.sideEffect('show as normal', (extent: this) => { + extent.updatePinUI(false); + }); + } + }); + // end::participant_pinned[] + + } + + updatePinUI(pinned: boolean) { + // update UI + } + + updateMuteUI(mute: boolean) { + // update UI + } + + muteParticipant(mute: boolean) { + // external api call + } +} \ No newline at end of file diff --git a/doc-site/examples/typescript/BGExamples/LoginExtent.ts b/doc-site/examples/typescript/BGExamples/LoginExtent.ts new file mode 100644 index 0000000..33745f7 --- /dev/null +++ b/doc-site/examples/typescript/BGExamples/LoginExtent.ts @@ -0,0 +1,301 @@ +import { Graph, InitialEvent } from './behaveg/behavegjs'; +import { Behavior } from "./behaveg/behavior" +import { State, Moment } from "./behaveg/resource" +import { Extent } from "./behaveg/extent" + +// tag::login_enable_extent[] +class LoginExtent extends Extent { + email: State; + password: State; +// end::login_enable_extent[] + + loggingIn: State + emailValid: State + passwordValid: State + loginEnabled: State + loginClick: Moment; + returnKey: Moment; + loginComplete: Moment; + + // tag::login_enable_init[] + constructor(graph: Graph) { + super(graph); + + this.email = new State("", this); + this.password = new State("", this); + + // tag::login_enable_behavior[] + this.makeBehavior([this.email, this.password], [], (extent: LoginExtent) => { + // end::login_enable_init[] + const email = extent.email.value; + const password = extent.password.value; + const hasPassword = password.length > 0; + const loginEnabled = extent.validEmailAddress(email) && hasPassword; + extent.sideEffect('enable login button', (extent) => { + extent.enableLoginButton(loginEnabled); + }); + }); + // end::login_enable_behavior[] + } + + constructorComplete(graph: Graph) { + + this.loggingIn = new State(false, this); + + // tag::login_complete_email[] + this.emailValid = new State(false, this); + this.makeBehavior([this.email], [this.emailValid], (extent: this) => { + const email = extent.email.value; + const emailValid = extent.validEmailAddress(email); + extent.emailValid.update(emailValid, true); + }); + // end::login_complete_email[] + + this.passwordValid = new State(false, this); + this.makeBehavior([this.password], [this.passwordValid], (extent: this) => { + const password = extent.password.value; + const passwordValid = password.length > 0; + extent.passwordValid.update(passwordValid, true); + }); + + // tag::login_complete_enable[] + this.loginEnabled = new State(false, this); + this.makeBehavior([this.emailValid, this.passwordValid, this.loggingIn], [this.loginEnabled], (extent: this) => { + const enabled = extent.emailValid.value && extent.passwordValid.value && !extent.loggingIn.value; + extent.loginEnabled.update(enabled, true); + extent.sideEffect('enable login button', (extent: this) => { + extent.enableLoginButton(extent.loginEnabled.value); + }); + }); + // end::login_complete_enable[] + + // tag::login_complete_login[] + this.loginClick = new Moment(this); + this.returnKey = new Moment(this); + this.loginComplete = new Moment(this); + this.makeBehavior([this.loginClick, this.returnKey, this.loginComplete], [this.loggingIn], (extent: this) => { + if ((extent.loginClick.justUpdated || extent.returnKey.justUpdated) && + extent.loginEnabled.traceValue) { + // Start login + extent.loggingIn.update(true, true); + } else if (extent.loginComplete.justUpdated && + !extent.loginComplete.value && + extent.loggingIn.value) { + // Login failed + extent.loggingIn.update(false, true); + } + + if (extent.loggingIn.justUpdatedTo(true)) { + extent.sideEffect('login api call', (extent: this) => { + extent.doLogin(extent.email.value, extent.password.value, (success: boolean) => { + extent.action('login call returned', () => { + extent.loginComplete.update(success); + }); + }); + }); + } + }); + // end::login_complete_login[] + + // Dont delete; its used in the documentation + // this has an example of requireSync + /* + this.makeBehavior([this.loginClick, this.returnKey, this.loginComplete], [this.loggingIn], (extent: this) => { + if ((extent.loginClick.justUpdated || extent.returnKey.justUpdated) && + extent.loginEnabled.traced.value) { + // Start login + extent.loggingIn.update(true, true); + } else if (extent.loginComplete.justUpdated && + !extent.loginComplete.value && + extent.loggingIn.value) { + // Login failed + extent.loggingIn.update(false, true); + } + + if (extent.loggingIn.justUpdatedTo(true)) { + // tag::login_complete_loginalt[] + extent.sideEffect('login api call', (extent: this) => { + extent.doLogin(extent.email.value, extent.password.value, (success: boolean) => { + extent.actionAsync('login call returned', () => { + extent.loginComplete.update(success); + }); + }); + }); + // end::login_complete_loginalt[] + } + }); + */ + + + } + + constructorShort(graph) { + + // tag::login_intro_short1[] + makeBehavior([email, password], [loginEnabled], (extent) => { + + const emailValid = validEmailAddress(email.value); + const passwordValid = password.value.length > 0; + const enabled = emailValid && passwordValid; + loginEnabled.update(enabled); + + }); + // end::login_intro_short1[] + + + // tag::login_intro_short2[] + makeBehavior([loginClick], [loggingIn], (extent) => { + if (loginClick.justUpdated && !loggingIn.value) { + loggingIn.update(true); + } + }); + + makeBehavior([email, password, loggingIn], [loginEnabled], (extent) => { + + const emailValid = validEmailAddress(email.value); + const passwordValid = password.value.length > 0; + const enabled = emailValid && passwordValid & !loggingIn.value; + loginEnabled.update(enabled); + + }); + // end::login_intro_short2[] + + // tag::login_intro_action[] + loginButton.onClick = () => { + action("login button clicked", () => { + loginClick.update(); + }); + }; + // end::login_intro_action[] + + // tag::login_intro_sideeffect[] + makeBehavior([email, password, loggingIn], [loginEnabled], (extent) => { + + const emailValid = validEmailAddress(email.value); + const passwordValid = password.value.length > 0; + const enabled = emailValid && passwordValid & !loggingIn.value; + loginEnabled.update(enabled); + + extent.sideEffect("login button enabled", (extent) => { + loginButton.enabled = loginEnabled.value; + }); + + }); + // end::login_intro_sideeffect[] + + } + + constructorCompleteShort(graph: Graph) { + + // tag::login_complete_short[] + this.email = new State(this, ""); + this.password = new State(this, ""); + this.loggingIn = new State(this, false); + + this.loginEnabled = new State(this, false); + this.makeBehavior([this.email, this.password, this.loggingIn], + [this.loginEnabled], + (extent: this) => { + const emailValid = extent.validEmailAddress(this.email.value); + const passwordValid = extent.password.value.length > 0; + const enabled = emailValid && passwordValid && !extent.loggingIn.value; + extent.loginEnabled.update(enabled, true); + extent.sideEffect('enable login button', (extent: this) => { + extent.enableLoginButton(extent.loginEnabled.value); + }); + }); + + this.loginClick = new Moment(this); + this.loginComplete = new Moment(this); + this.makeBehavior([this.loginClick, this.loginComplete], + [this.loggingIn], + (extent: this) => { + if (extent.loginClick.justUpdated && + extent.loginEnabled.traceValue) { + // Start login + extent.loggingIn.update(true, true); + } else if (extent.loginComplete.justUpdated && + !extent.loginComplete.value && + extent.loggingIn.value) { + // Login failed + extent.loggingIn.update(false, true); + } + + if (extent.loggingIn.justUpdatedTo(true)) { + extent.sideEffect('login api call', (extent: this) => { + extent.doLogin(extent.email.value, extent.password.value, (success: boolean) => { + extent.actionAsync('login call returned', () => { + extent.loginComplete.update(success); + }); + }); + }); + } + }); + // end::login_complete_short[] + } + + validEmailAddress(email: string) : boolean { + return email.length > 0 && email.includes('@'); + } + + doLogin(email: string, password: string, complete: (boolean) => void) { + // login api calls + }; + + enableLoginButton(enabled: boolean) { + // side effect to set the enabled state of the login button + } + + // tag::login_sequence_compare[] + emailChangedSincePassword() : boolean { + return this.email.event.sequence > this.password.event.sequence; + } + // end::login_sequence_compare[] + + // tag::login_timestamp[] + loginCompletedWhen() : Date { + return this.loginComplete.event.timestamp; + } + // end::login_timestamp[] + +} + +class LoginPage { + + graph: Graph; + loginExtent: LoginExtent; + + constructor() { + // tag::login_enable_setup[] + this.graph = new Graph(); + this.loginExtent = new LoginExtent(this.graph); + this.graph.action('new login page', () => { + this.loginExtent.addToGraph(); + }); + // end::login_enable_setup[] + } + + // tag::login_enable_actions[] + didUpdateEmailField(contents: string) { + this.graph.action('update email field', () => { + this.loginExtent.email.update(contents, true); + }); + } + + didUpdatePasswordField(contents: string) { + this.graph.action('update password field', () => { + this.loginExtent.password.update(contents, true); + }); + } + // end::login_enable_actions[] + + // tag::login_complete_click[] + loginButtonClicked() { + this.graph.action('login button clicked', () => { + this.loginExtent.loginClick.update(); + }); + } + // end::login_complete_click[] + + +} diff --git a/doc-site/examples/typescript/BGExamples/behaveg/behavegjs.ts b/doc-site/examples/typescript/BGExamples/behaveg/behavegjs.ts new file mode 100644 index 0000000..da518cf --- /dev/null +++ b/doc-site/examples/typescript/BGExamples/behaveg/behavegjs.ts @@ -0,0 +1,522 @@ +import { BufferedPriorityQueue } from "./bufferedqueue"; +import { Behavior } from "./behavior"; +import { Extent } from "./extent"; +import { Resource } from "./resource"; + +export enum OrderingState { + Unordered, + Ordering, + Ordered +} + +export enum ValuePersistence { + Persistent, + Transient, + TransientTrace +} + +interface SideEffect { + debugName: string | null; + block: (extent: Extent) => void; + extent: Extent; +} + +interface Action { + impulse: string | null; + block: () => void; +} + +export interface BehaviorGraphDateProvider { + now() : Date +} + +const DefaultDateProvider = { + now: () => { return new Date(); } +} + +export class Graph { + dateProvider: BehaviorGraphDateProvider; + currentEvent: GraphEvent | null = null; + lastEvent: GraphEvent; + activatedBehaviors: BufferedPriorityQueue = new BufferedPriorityQueue(); + currentBehavior: Behavior | null = null; + effects: SideEffect[] = []; + actions: Action[] = []; + untrackedBehaviors: Behavior[] = []; + modifiedDemandBehaviors: Behavior[] = []; + modifiedSupplyBehaviors: Behavior[] = []; + updatedTransients: Transient[] = []; + needsOrdering: Behavior[] = []; + + constructor(timeProvider = DefaultDateProvider) { + this.lastEvent = InitialEvent; + this.dateProvider = timeProvider; + } + + actionAsync(impulse: string, block: () => void) { + this.actions.push({impulse: impulse, block: block}); + if (this.currentEvent == null) { + this.eventLoop(); + } + } + + action(impulse: string, block: () => void) { + this.actions.push({impulse: impulse, block: block}); + this.eventLoop(); + } + + eventLoop() { + + while(true) { + + try { + if (this.activatedBehaviors.length > 0 || + this.untrackedBehaviors.length > 0 || + this.modifiedDemandBehaviors.length > 0 || + this.modifiedSupplyBehaviors.length > 0 || + this.needsOrdering.length > 0) { + + let sequence = this.currentEvent!.sequence; + this.addUntrackedBehaviors(sequence); + this.addUntrackedSupplies(sequence); + this.addUntrackedDemands(sequence); + this.orderBehaviors(); + this.runNextBehavior(sequence); + + continue; + } + + let effect = this.effects.shift(); + if (effect) { + effect.block(effect.extent); + continue; + } + + if (this.currentEvent) { + this.clearTransients(); + this.lastEvent = this.currentEvent!; + this.currentEvent = null; + this.currentBehavior = null; + } + + let action = this.actions.shift(); + if (action) { + let newEvent = new GraphEvent(this.lastEvent.sequence + 1, this.dateProvider.now(), action.impulse); + this.currentEvent = newEvent; + action.block(); + continue; + } + + } catch (error) { + this.currentEvent = null; + this.actions.length = 0; + this.effects.length = 0; + this.currentBehavior = null; + this.activatedBehaviors.clear(); + this.clearTransients(); + this.modifiedDemandBehaviors.length = 0; + this.modifiedSupplyBehaviors.length = 0; + this.untrackedBehaviors.length = 0; + throw(error); + } + // no more tasks so we can exit the event loop + break; + } + } + + clearTransients() { + if (this.updatedTransients.length > 0) { + for (let transient of this.updatedTransients) { + transient.clear(); + } + this.updatedTransients.length = 0; + } + } + trackTransient(resource: Transient) { + this.updatedTransients.push(resource); + } + + resourceTouched(resource: Resource) { + if (this.currentEvent != null) { + for (let subsequent of resource.subsequents) { + this.activateBehavior(subsequent, this.currentEvent.sequence); + } + } + } + + activateBehavior(behavior: Behavior, sequence: number) { + if (behavior.enqueuedWhen == null || behavior.enqueuedWhen < sequence) { + behavior.enqueuedWhen = sequence; + this.activatedBehaviors.push(behavior); + } + } + + runNextBehavior(sequence: number) { + // need to sort the behaviors + // but a buffered heap would be nicer + + let behavior = this.activatedBehaviors.pop(); + if (behavior != undefined && behavior.removedWhen != sequence) { + this.currentBehavior = behavior; + behavior.block(behavior.extent); + this.currentBehavior = null; + } + } + + sideEffect(extent: Extent, name: string | null, block: (extent: Extent) => void) { + if (this.currentEvent == null) { + let err: any = new Error("Effects can only be added during an event loop."); + throw err; + } else { + this.effects.push({ debugName: name, block: block, extent: extent }); + } + } + + addUntrackedBehaviors(sequence: number) { + if (this.untrackedBehaviors.length > 0) { + for (let behavior of this.untrackedBehaviors) { + this.activateBehavior(behavior, sequence); + this.modifiedDemandBehaviors.push(behavior); + this.modifiedSupplyBehaviors.push(behavior); + } + this.untrackedBehaviors = []; + } + } + + addUntrackedSupplies(sequence: number) { + if (this.modifiedSupplyBehaviors.length > 0) { + for (let behavior of this.modifiedSupplyBehaviors) { + if (behavior.untrackedSupplies != null) { + if (behavior.supplies != null) { + for (let existingSupply of behavior.supplies) { + existingSupply.suppliedBy = null; + } + } + behavior.supplies = new Set(behavior.untrackedSupplies); + for (let newSupply of behavior.supplies) { + if (newSupply.suppliedBy != null && newSupply.suppliedBy != behavior) { + let err: any = new Error("Resource cannot be supplied by more than one behavior."); + err.alreadySupplied = newSupply; + err.desiredSupplier = behavior; + throw err; + } + newSupply.suppliedBy = behavior; + } + behavior.untrackedSupplies = null; + // technically this doesn't need reordering but its subsequents will + // setting this to reorder will also adjust its subsequents if necessary + // in the sortDFS code + this.needsOrdering.push(behavior); + } + } + this.modifiedSupplyBehaviors.length = 0; + } + } + + addUntrackedDemands(sequence: number) { + if (this.modifiedDemandBehaviors.length > 0) { + for (let behavior of this.modifiedDemandBehaviors) { + if (behavior.untrackedDemands != null) { + + let removedDemands: Resource[] | undefined; + if (behavior.demands != null) { + for (let demand of behavior.demands) { + if (!behavior.untrackedDemands.includes(demand)) { + if (removedDemands == undefined) { + removedDemands = []; + } + removedDemands.push(demand); + } + } + } + + let addedDemands: Resource[] | undefined; + for (let untrackedDemand of behavior.untrackedDemands) { + if (!untrackedDemand.added) { + let err: any = new Error("All demands must be added to the graph."); + err.currentBehavior = behavior; + err.untrackedDemand = untrackedDemand; + throw err; + } + if (behavior.demands == null || !behavior.demands.has(untrackedDemand)) { + if (addedDemands == undefined) { + addedDemands = []; + } + addedDemands.push(untrackedDemand); + } + } + + let needsRunning = false; + + if (removedDemands != undefined) { + needsRunning = true; + for (let demand of removedDemands) { + demand.subsequents.delete(behavior); + } + } + + let orderBehavior = behavior.orderingState == OrderingState.Unordered; + + if (addedDemands != undefined) { + needsRunning = true; + for (let demand of addedDemands) { + demand.subsequents.add(behavior); + + if (!orderBehavior) { + let prior = demand.suppliedBy; + if (prior != null && prior.orderingState == OrderingState.Ordered && prior.order >= behavior.order) { + orderBehavior = true; + } + } + } + } + + behavior.demands = new Set(behavior.untrackedDemands); + behavior.untrackedDemands = null; + + if (orderBehavior) { + this.needsOrdering.push(behavior); + } + if (needsRunning) { + this.activateBehavior(behavior, sequence); + } + } + + + } + this.modifiedDemandBehaviors.length = 0; + } + } + + orderBehaviors() { + // find all behaviors that need ordering and their + // subsequents and mark them all as needing ordering + + if (this.needsOrdering.length == 0) { return; } + + let localNeedsOrdering : Behavior[] = []; + let traversalQueue: Behavior[] = []; + + // first get behaviors that need ordering and mark them as + // ordered so they will be traversed when first encountered + for (let behavior of this.needsOrdering) { + behavior.orderingState = OrderingState.Ordered; + traversalQueue.push(behavior); + } + this.needsOrdering.length = 0; + + // dfs forward on each to find all that need ordering + while (traversalQueue.length > 0) { + let behavior = traversalQueue.shift(); + if (behavior != undefined) { + if (behavior.orderingState == OrderingState.Ordered) { + behavior.orderingState = OrderingState.Unordered; + localNeedsOrdering.push(behavior); + if (behavior.supplies) { + for (let supply of behavior.supplies) { + for (let subsequent of supply.subsequents) { + traversalQueue.push(subsequent); + } + } + } + } + } + } + + let needsReheap = { value: false }; // this allows out parameter + for (let behavior of localNeedsOrdering) { + this.sortDFS(behavior, needsReheap); + } + + if (needsReheap.value) { + this.activatedBehaviors.unsort() + } + } + + sortDFS(behavior: Behavior, needsReheap: { value: boolean }) { + if (behavior.orderingState == OrderingState.Ordering) { + let err: any = new Error("Behavior dependency cycle detected."); + err.currentBehavior = behavior; + err.cycle = this.cycleForBehavior(behavior); + throw err; + } + + if (behavior.orderingState == OrderingState.Unordered) { + behavior.orderingState = OrderingState.Ordering; + + let order = 0; + if (behavior.demands != null) { + for (let demand of behavior.demands) { + let prior = demand.suppliedBy; + if (prior != null) { + if (prior.orderingState != OrderingState.Ordered) { + this.sortDFS(prior, needsReheap); + } + order = Math.max(order, prior.order + 1); + } + } + } + + behavior.orderingState = OrderingState.Ordered; + + if (order != behavior.order) { + behavior.order = order; + needsReheap.value = true; + } + } + } + + cycleForBehavior(behavior: Behavior): Resource[] { + let stack: Resource[] = []; + if (this.cycleDFS(behavior, behavior, stack)) { + let output: Resource[] = []; + while (stack.length > 0) { + let rez = stack.pop(); + output.push(rez!); + } + return output; + } else { + return []; + } + } + + cycleDFS(currentBehavior: Behavior, target: Behavior, stack: Resource[]): boolean { + if (currentBehavior.demands != null) { + for (let r of currentBehavior.demands) { + stack.push(r) + let b = r.suppliedBy; + if (b != null) { + if (b == target) { + return true; + } + if (this.cycleDFS(b, target, stack)) { + return true; + } + stack.pop(); + } + } + } + return false; + } + + addBehavior(behavior: Behavior) { + behavior.added = true; + this.untrackedBehaviors.push(behavior) + } + + updateDemands(behavior: Behavior, newDemands: Resource[]) { + if (!behavior.added) { + let err: any = new Error("Behavior must belong to graph before updating demands."); + err.behavior = behavior; + throw err; + } else if (this.currentEvent == null) { + let err: any = new Error("Demands can only be updated during an event loop."); + err.behavior = behavior; + throw err; + } + behavior.untrackedDemands = newDemands; + this.modifiedDemandBehaviors.push(behavior); + } + + updateSupplies(behavior: Behavior, newSupplies: Resource[]) { + if (!behavior.added) { + let err: any = new Error("Behavior must belong to graph before updating supplies."); + err.behavior = behavior; + throw err; + } else if (this.currentEvent == null) { + let err: any = new Error("Supplies can only be updated during an event loop."); + err.behavior = behavior; + throw err; + } + behavior.untrackedSupplies = newSupplies; + this.modifiedSupplyBehaviors.push(behavior); + } + + removeBehavior(behavior: Behavior, sequence: number) { + if (behavior.supplies != null) { + // remove all behaviors supplies from subsequents demands + for (let supply of behavior.supplies) { + for (let subsequent of supply.subsequents) { + if (subsequent.demands != null) { + subsequent.demands.delete(supply); + } + } + supply.subsequents.clear(); + } + } + + if (behavior.demands != null) { + for (let demand of behavior.demands) { + if (demand.subsequents != null) { + demand.subsequents.delete(behavior); + } + } + behavior.demands.clear(); + } + + behavior.removedWhen = sequence; + behavior.added = false; + } + + addResource(resource: Resource) { + resource.added = true; + } + + addExtent(extent: Extent) { + if (extent.addedToGraphWhen != null) { + let err: any = new Error("Extent already belongs to a graph."); + err.extent = extent; + err.graph = this; + throw err; + } + if (this.currentEvent == null) { + let err: any = new Error("Extents can only be added during an event loop."); + err.extent = extent; + throw err; + } else { + extent.graph = this; + extent.addedToGraphWhen = this.currentEvent.sequence; + for (let resource of extent.resources) { + this.addResource(resource); + } + for (let behavior of extent.behaviors) { + this.addBehavior(behavior); + } + } + } + + removeExtent(extent: Extent) { + if (this.currentEvent == null) { + let err: any = new Error("Extents can only be removed during an event loop."); + err.extent = extent; + throw err; + } else { + for (let resource of extent.resources) { + resource.added = false; + } + for (let behavior of extent.behaviors) { + this.removeBehavior(behavior, this.currentEvent.sequence); + } + extent.addedToGraphWhen = null; + } + } +} + +export class GraphEvent { + sequence: number; + timestamp: Date; + impulse: string | null; + + constructor(sequence: number, timestamp: Date, impulse: string | null) { + this.sequence = sequence; + this.timestamp = timestamp; + this.impulse = impulse; + } +} + +export const InitialEvent: GraphEvent = new GraphEvent(0, new Date(0), "InitialEvent"); + +export interface Transient { + clear(): void; +} + diff --git a/doc-site/examples/typescript/BGExamples/behaveg/behavior.ts b/doc-site/examples/typescript/BGExamples/behaveg/behavior.ts new file mode 100644 index 0000000..b389fc0 --- /dev/null +++ b/doc-site/examples/typescript/BGExamples/behaveg/behavior.ts @@ -0,0 +1,41 @@ +import {Orderable} from "./bufferedqueue"; +import {Extent, Named} from "./extent"; +import {Resource} from "./resource"; +import {OrderingState} from "./behavegjs" + +export class Behavior implements Named, Orderable { + demands: Set | null; + supplies: Set | null; + block: (extent: Extent) => void; + debugName: string | null = null; + enqueuedWhen: number | null; + runWhen: number | null; + removedWhen: number | null = null; + added: boolean = false; + extent: Extent; + orderingState: OrderingState = OrderingState.Unordered; + order: number = 0; + + untrackedDemands: Resource[] | null; + untrackedSupplies: Resource[] | null; + + constructor(extent: Extent, demands: Resource[] | null, supplies: Resource[] | null, block: (extent: Extent) => void) { + this.extent = extent; + extent.addBehavior(this); + this.demands = null; + this.supplies = null; + this.block = block; + this.enqueuedWhen = null; + this.runWhen = null; + this.untrackedDemands = demands; + this.untrackedSupplies = supplies; + } + + setDemands(newDemands: Resource[]) { + this.extent.graph.setDemands(this, newDemands); + } + + setSupplies(newSupplies: Resource[]) { + this.extent.graph.setSupplies(this, newSupplies); + } +} diff --git a/doc-site/examples/typescript/BGExamples/behaveg/bufferedqueue.ts b/doc-site/examples/typescript/BGExamples/behaveg/bufferedqueue.ts new file mode 100644 index 0000000..56f8944 --- /dev/null +++ b/doc-site/examples/typescript/BGExamples/behaveg/bufferedqueue.ts @@ -0,0 +1,100 @@ +export interface Orderable { + order: number; +} + +export class BufferedPriorityQueue { + /* + A binary heap implementation that works for specifically for behaviors. + Delays heapifying new elements until the next pop. Adding multiple extents + in the same behavior can lead to reheaping. The delay prevents behaviors + from being resorted multiple times. + */ + queue: T[] = []; + buffer: T[] = []; + + constructor() { + + } + + public push(behavior: T) : void { + this.buffer.push(behavior); + } + + public pop() : T | undefined { + if (this.length == 0) { + return undefined; + } else { + // heapify elements in the buffer + while (true) { + let b = this.buffer.shift(); + if (b != undefined) { + this.queue.push(b); + if (this.queue.length > 1) { + this.up(this.queue.length - 1); + } + } else { + break; + } + } + + let b = this.queue.shift(); + if (this.queue.length > 0) { + this.down(0); + } + return b; + + } + } + + public get length() : number { + return this.queue.length + this.buffer.length; + } + + public unsort() : void { + this.buffer = this.buffer.concat(this.queue); + this.queue.length = 0; + } + + public clear() : void { + this.queue.length = 0; + this.buffer.length = 0; + } + + private up(pos: number) { + let b_up = this.queue[pos]; + while (pos > 0) { + let parent = (pos - 1) >> 1; + let b_parent = this.queue[parent]; + if (b_up.order >= b_parent.order) { + break; + } + this.queue[pos] = b_parent; + pos = parent; + } + this.queue[pos] = b_up; + } + + private down(pos: number) { + const halfLength = this.queue.length >> 1; + const b_down = this.queue[pos]; + + while (pos < halfLength) { + let left = (pos << 1) + 1; + let best = this.queue[left]; + const right = left + 1; + + if (right < this.queue.length && this.queue[right].order < best.order) { + left = right; + best = this.queue[right]; + } + if (best.order >= b_down.order) { + break; + } + this.queue[pos] = best; + pos = left; + } + + this.queue[pos] = b_down; + } + +} diff --git a/doc-site/examples/typescript/BGExamples/behaveg/extent.ts b/doc-site/examples/typescript/BGExamples/behaveg/extent.ts new file mode 100644 index 0000000..4a21e52 --- /dev/null +++ b/doc-site/examples/typescript/BGExamples/behaveg/extent.ts @@ -0,0 +1,115 @@ +import {Graph} from "./behavegjs"; +import {Behavior} from "./behavior"; +import {Resource} from "./resource"; + +export interface Named { + debugName: string | null; +} + +function isNamed(arg: any): arg is Named { + return (arg as Named).debugName !== undefined; +} + +export class Extent implements Named { + debugName: string | null; + behaviors: Behavior[] = []; + resources: Resource[] = []; + graph: Graph; + addedToGraphWhen: number | null = null; + + constructor(graph: Graph) { + this.debugName = this.constructor.name; + this.graph = graph; + } + + addBehavior(behavior: Behavior) { + this.behaviors.push(behavior); + } + + addResource(resource: Resource) { + this.resources.push(resource); + } + + addToGraphWithAction() { + this.graph.action('add extent: ' + this.debugName, () => { this.addToGraph(); }); + } + + addToGraph() { + if (this.graph.currentEvent != null) { + this.collectAndNameComponents(); + this.graph.addExtent(this); + } else { + let err: any = new Error("addToGraph must be called within an event loop."); + err.extent = this; + throw err; + } + } + + removeFromGraphWithAction() { + this.graph.action('remove extent: ' + this.debugName, () => { this.removeFromGraph(); }); + } + + removeFromGraph() { + let graph = this.graph; + if (graph.currentEvent != null) { + if (this.addedToGraphWhen != null) { + graph.removeExtent(this); + } + } else { + let err: any = new Error("removeFromGraph must be called within an event loop."); + err.extent = this; + throw err; + } + } + + collectAndNameComponents() { + // automatically add any behaviors and resources that are contained + // by this Extent object and name them with corresponding keys + for (let key in this) { + let object = this[key]; + if (object == null || object == undefined) { continue; } + if (isNamed(object)) { + if (object.debugName == null) { + object.debugName = key; + } + } + + if (object instanceof Behavior && object.extent == null) { + this.addBehavior(object); + } else if (object instanceof Resource && object.extent == null) { + this.addResource(object); + } + } + } + + makeBehavior(demands: Resource[] | null, supplies: Resource[] | null, block: (extent: this) => void): Behavior { + let behavior = new Behavior(this, demands, supplies, block as (extent: Extent) => void); + return behavior; + } + + sideEffect(name: string | null, block: (extent: this) => void) { + if (this.addedToGraphWhen != null) { + this.graph.sideEffect(this, name, block as (extent: Extent) => void); + } + } + + actionAsync(impulse: string, action: () => void) { + if (this.addedToGraphWhen != null) { + this.graph.actionAsync(impulse, action); + } else { + let err: any = new Error("Action on extent requires it be added to the graph."); + err.extent = this; + throw err; + } + } + + action(impulse: string, action: () => void) { + if (this.addedToGraphWhen != null) { + this.graph.action(impulse, action); + } else { + let err: any = new Error("Action on extent requires it be added to the graph."); + err.extent = this; + throw err; + } + } +} diff --git a/doc-site/examples/typescript/BGExamples/behaveg/resource.ts b/doc-site/examples/typescript/BGExamples/behaveg/resource.ts new file mode 100644 index 0000000..5b0363d --- /dev/null +++ b/doc-site/examples/typescript/BGExamples/behaveg/resource.ts @@ -0,0 +1,194 @@ +import {Behavior} from "./behavior"; +import {Extent, Named} from "./extent"; +import {GraphEvent, Graph, Transient, InitialEvent} from "./behavegjs"; + +export class Resource implements Named { + debugName: string | null = null; + + extent: Extent; + graph: Graph; + added: boolean = false; + subsequents: Set = new Set(); + suppliedBy: Behavior | null = null; + + constructor(extent: Extent, name?: string) { + this.extent = extent; + this.graph = extent.graph; + extent.addResource(this); + if (name !== undefined) { + this.debugName = name; + } + } + + assertValidUpdater() { + let graph = this.graph; + let currentBehavior = graph.currentBehavior; + let currentEvent = graph.currentEvent; + if (currentBehavior == null && currentEvent == null) { + let err: any = new Error("Resource must be updated inside a behavior or action"); + err.resource = this; + throw err; + } + if (this.suppliedBy && currentBehavior != this.suppliedBy) { + let err: any = new Error("Supplied resource can only be updated by its supplying behavior."); + err.resource = this; + err.currentBehavior = currentBehavior; + throw err; + } + if (this.suppliedBy == null && currentBehavior != null) { + let err: any = new Error("Unsupplied resource can only be updated in an action."); + err.resource = this; + err.currentBehavior = currentBehavior; + throw err; + } + } +} + +export class Moment extends Resource implements Transient { + private _happened: boolean = false; + private _happenedValue: T | undefined = undefined; + private _happenedWhen: GraphEvent | null = null; + + get justUpdated(): boolean { + return this._happened; + } + + get value(): T | undefined { + return this._happenedValue; + } + + get event(): GraphEvent | null { + return this._happenedWhen; + } + + updateWithAction(value: T | undefined = undefined) { + this.graph.action(this.debugName ?? ("Impulse From happen(): " + this), () => { + this.update(value); + }); + return; + } + + update(value: T | undefined = undefined) { + this.assertValidUpdater(); + this._happened = true; + this._happenedValue = value; + this._happenedWhen = this.graph.currentEvent; + this.graph.resourceTouched(this); + this.graph.trackTransient(this); + } + + clear(): void { + this._happened = false; + this._happenedValue = undefined; + } + +} + +export type StateHistory = { value: T, event: GraphEvent }; +export class State extends Resource implements Transient { + private history: StateHistory[] = []; + private historyLength: number = 1; + + constructor(initialState: T, extent: Extent, name?: string) { + super(extent, name); + this.history.unshift({ value: initialState, event: InitialEvent }); + } + + updateWithAction(newValue: T, changesOnly: boolean) { + this.graph.action(this.debugName ?? ("Impulse From updateValue(): " + this), () => { + this.update(newValue, changesOnly); + }); + return; + } + + update(newValue: T, changesOnly: boolean) { + this.assertValidUpdater(); + + if (changesOnly) { + if (this.history[0].value == newValue) { + return; + } + } + this.history.unshift({ value: newValue, event: this.graph.currentEvent! }); + this.graph.resourceTouched(this); + this.graph.trackTransient(this); + } + + clear(): void { + this.history.length = this.historyLength; + } + + get value(): T { + return this.history[0].value; + } + + get event(): GraphEvent { + return this.history[0].event; + } + + get trace(): StateHistory { + let evt = this.graph?.currentEvent; + let current = this.history[0]; + if (evt) { + if (evt.sequence == current.event.sequence) { + return this.history[1]; + } + } else { + let err: any = new Error("Traced state can only be accessed during event loop."); + err.resource = this; + throw err; + } + return current; + } + + get traceValue(): T { + return this.trace.value; + } + + get traceEvent(): GraphEvent { + return this.trace.event; + } + + historyAt(event: GraphEvent): { value: T, event: GraphEvent } | undefined { + if (event) { + for (let h of this.history) { + if (h.event.sequence <= event.sequence) { + return h; + } + } + return undefined; + } + } + + get justUpdated(): boolean { + return this.justUpdatedToFrom(undefined, undefined); + } + + justUpdatedTo(toState: T): boolean { + return this.justUpdatedToFrom(toState, undefined); + } + + justUpdatedFrom(fromState: T): boolean { + return this.justUpdatedToFrom(undefined, fromState); + } + + justUpdatedToFrom(toState: T | undefined, fromState: T | undefined): boolean { + let evt = this.graph?.currentEvent; + if (evt) { + if (this.history.length > 1) { + let s = this.history[0]; + let changed = evt.sequence == s.event.sequence; + if (toState != undefined) { + changed = changed && s.value == toState; + } + if (fromState != undefined) { + let p = this.history[1]; + changed = changed && p.value == fromState; + } + return changed; + } + } + return false; + } +} + diff --git a/doc-site/layouts/404.html b/doc-site/layouts/404.html new file mode 100644 index 0000000..378b736 --- /dev/null +++ b/doc-site/layouts/404.html @@ -0,0 +1,10 @@ +{{ define "main"}} +
+
+

Not found

+

Oops! This page doesn't exist. Try going back to our home page.

+ +

You can learn how to make a 404 page like this in Custom 404 Pages.

+
+
+{{ end }} diff --git a/doc-site/layouts/shortcodes/static.html b/doc-site/layouts/shortcodes/static.html new file mode 100644 index 0000000..097d8c2 --- /dev/null +++ b/doc-site/layouts/shortcodes/static.html @@ -0,0 +1,5 @@ +{{- .Scratch.Set "path" (.Get 0) -}} +{{- if hasPrefix (.Scratch.Get "path") "/" -}} + {{- .Scratch.Set "path" (slicestr (.Scratch.Get "path") 1) -}} +{{- end -}} +{{- .Scratch.Get "path" | relURL -}} \ No newline at end of file diff --git a/doc-site/layouts/shortcodes/term.html b/doc-site/layouts/shortcodes/term.html new file mode 100644 index 0000000..9f495cc --- /dev/null +++ b/doc-site/layouts/shortcodes/term.html @@ -0,0 +1 @@ +{{ index .Site.Data.terms (.Page.Params.Get "language") (.Get 0) }} \ No newline at end of file diff --git a/doc-site/netlify.toml b/doc-site/netlify.toml new file mode 100644 index 0000000..0e94eba --- /dev/null +++ b/doc-site/netlify.toml @@ -0,0 +1,3 @@ +[build] +[build.environment] +HUGO_VERSION = "0.88.1" diff --git a/doc-site/package.json b/doc-site/package.json new file mode 100644 index 0000000..960eee9 --- /dev/null +++ b/doc-site/package.json @@ -0,0 +1,24 @@ +{ + "name": "tech-doc-hugo", + "version": "0.0.1", + "description": "Hugo theme for technical documentation.", + "main": "none.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/google/docsy-example.git" + }, + "author": "", + "license": "ISC", + "bugs": { + "url": "https://github.com/google/docsy-example/issues" + }, + "homepage": "https://github.com/google/docsy-example#readme", + "devDependencies": { + "autoprefixer": "^10.4.0", + "postcss": "^8.3.7", + "postcss-cli": "^9.0.2" + } +} diff --git a/doc-site/static/images/graph_example.png b/doc-site/static/images/graph_example.png new file mode 100644 index 0000000..d0743d9 Binary files /dev/null and b/doc-site/static/images/graph_example.png differ diff --git a/doc-site/static/images/login-intro-graph.svg b/doc-site/static/images/login-intro-graph.svg new file mode 100644 index 0000000..41a0daf --- /dev/null +++ b/doc-site/static/images/login-intro-graph.svg @@ -0,0 +1,147 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Produced by OmniGraffle 7.18.4\n2021-04-07 19:15:33 +0000 + + Login Graph + + + Temperature + + + + + Login Enabled + Behavior + + + + + + + + + + Logging In + Behavior + + + + + + loginClick + + + + + + + + + + + + + + + loggingIn + + + + + + + + + + + + + + + password + + + + + + + + + + email + + + + + + + + + + + + + + Login + + + + + + + loginEnabled + + + + + + + + + + + Login Button + Enabled + + + + + diff --git a/doc-site/static/images/login-ui-2.svg b/doc-site/static/images/login-ui-2.svg new file mode 100644 index 0000000..a78dae1 --- /dev/null +++ b/doc-site/static/images/login-ui-2.svg @@ -0,0 +1,69 @@ + + + + + + + + + + + Produced by OmniGraffle 7.18.4\n2021-04-07 17:51:22 +0000 + + Login Screen + + Layer 1 + + + + + + + + + + + Excellent Application + + + + + + + Customer Login + + + + + Email + + + + + + + Login + + + + + + + sal897@yahoo.com + + + + + + + ********* + + + + + Password + + + + + diff --git a/doc-site/static/images/login_multipage.png b/doc-site/static/images/login_multipage.png new file mode 100644 index 0000000..6ff11f1 Binary files /dev/null and b/doc-site/static/images/login_multipage.png differ diff --git a/doc-site/static/images/login_simple_diagram.png b/doc-site/static/images/login_simple_diagram.png new file mode 100644 index 0000000..7447e95 Binary files /dev/null and b/doc-site/static/images/login_simple_diagram.png differ diff --git a/doc-site/static/images/login_ui.png b/doc-site/static/images/login_ui.png new file mode 100644 index 0000000..28eb9bb Binary files /dev/null and b/doc-site/static/images/login_ui.png differ diff --git a/doc-site/static/images/login_ui_complete.png b/doc-site/static/images/login_ui_complete.png new file mode 100644 index 0000000..1731bcd Binary files /dev/null and b/doc-site/static/images/login_ui_complete.png differ diff --git a/doc-site/static/images/thermostat-heat.svg b/doc-site/static/images/thermostat-heat.svg new file mode 100644 index 0000000..b054f3a --- /dev/null +++ b/doc-site/static/images/thermostat-heat.svg @@ -0,0 +1,143 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Produced by OmniGraffle 7.18.4\n2021-04-07 18:44:20 +0000 + + TempSet + + + Heat + + + + + Heating + Behavior + + + + + + + + + Current + Temperature + + + + + + + + + + + + + + + + + Heating + Equipment + + + + + + + + + + + + + + + Temperature + + + + + Temperature + Behavior + + + + + + Up Button + Press + + + + + + + + + + + + + + + Desired Temperature + Resource + + + + + + Down Button + Press + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc-site/static/images/thermostat-temp.svg b/doc-site/static/images/thermostat-temp.svg new file mode 100644 index 0000000..0e6c22c --- /dev/null +++ b/doc-site/static/images/thermostat-temp.svg @@ -0,0 +1,94 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Produced by OmniGraffle 7.18.4\n2021-04-07 18:45:51 +0000 + + TempSet + + + Temperature + + + + + Temperature + Behavior + + + + + + Up Button + Press + + + + + + + + + + + + + + + Desired Temperature + Resource + + + + + + Down Button + Press + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc-site/static/images/thermostat-ui.png b/doc-site/static/images/thermostat-ui.png new file mode 100644 index 0000000..f48dc02 Binary files /dev/null and b/doc-site/static/images/thermostat-ui.png differ diff --git a/doc-site/static/images/thermostat-wall.svg b/doc-site/static/images/thermostat-wall.svg new file mode 100644 index 0000000..6459b00 --- /dev/null +++ b/doc-site/static/images/thermostat-wall.svg @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + Produced by OmniGraffle 7.18.4\n2021-04-06 22:49:36 +0000 + + Thermostat + + Layer 1 + + + + + + + + Tempwell + + + + + + + + + + + 65° + + + + + 69° + + + + + Current + + + + + Heat + + + + + + + + + + + + Up + + + + + + + + + + + Down + + + + + + + + + diff --git a/doc-site/static/images/todolist.png b/doc-site/static/images/todolist.png new file mode 100644 index 0000000..b908776 Binary files /dev/null and b/doc-site/static/images/todolist.png differ diff --git a/doc-site/static/images/video_chat_diagram.png b/doc-site/static/images/video_chat_diagram.png new file mode 100644 index 0000000..beda14b Binary files /dev/null and b/doc-site/static/images/video_chat_diagram.png differ diff --git a/doc-site/static/images/video_chat_ui.png b/doc-site/static/images/video_chat_ui.png new file mode 100644 index 0000000..73e31ca Binary files /dev/null and b/doc-site/static/images/video_chat_ui.png differ diff --git a/doc-site/themes/docsy b/doc-site/themes/docsy new file mode 160000 index 0000000..7dc7083 --- /dev/null +++ b/doc-site/themes/docsy @@ -0,0 +1 @@ +Subproject commit 7dc70837461881b639215e40d90b6502974e3a14 diff --git a/docs/typescript/404.html b/docs/typescript/404.html new file mode 100644 index 0000000..64155ce --- /dev/null +++ b/docs/typescript/404.html @@ -0,0 +1,138 @@ + + + + + + + + + + + + + + + + + + + + +404 Page not found | Behavior Graph + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+
+
+ +
+
+

Not found

+

Oops! This page doesn't exist. Try going back to our home page.

+ +

You can learn how to make a 404 page like this in Custom 404 Pages.

+
+
+ +
+ +
+
+
+
+ +
+
+ +
+
+ © 2022 Yahoo All Rights Reserved + + + + +
+
+
+
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/typescript/api/index.html b/docs/typescript/api/index.html new file mode 100644 index 0000000..c0f287e --- /dev/null +++ b/docs/typescript/api/index.html @@ -0,0 +1,853 @@ + + + + + + + + + + + + + + + + + + + + +API | Behavior Graph + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+
+
+
+ + +
+ + + + + +
+

API

+ + +

Types

+

Behavior

+

A behavior is a block of code together with its dependency relationships (links). +They are one of the two node types in a behavior graph. +You define behaviors using the behavior() factory method of an Extent.

+

Behaviors have both static and dynamic links. +You provide static links when you create the behavior. +Behavior Graph will update dynamic links per special methods on BehaviorBuilder or you can update them directly on a behavior.

+

demands

+
    +
  • returns: Set<Resource> | null
  • +
  • read only property
  • +
+

The current set of all Resources which the behavior demands.

+

extent

+
    +
  • returns: Extent
  • +
  • read only property
  • +
+

A behavior always has an Extent with which it is created.

+

setDynamicDemands()

+
    +
  • param: newDemands: (Demandable | undefined)[] | null)
  • +
+

Provide an array of Demandables. +undefined is also an element type to make for easier use of optional chaining. +Providing null is equivalent to saying there are no dynamic demands.

+

setDynamicSupplies()

+
    +
  • param: newSupplies: (Resource | undefined)[] | null)
  • +
+

Provide an array of Resources to supply. +undefined is also an element type to make for easier use of optional chaining. +Providing null is equivalent to saying there are no dynamic supplies.

+

supplies

+
    +
  • returns: Set<Resource> | null
  • +
  • read only property
  • +
+

The current set of all Resources which the behavior supplies.

+

BehaviorBuilder

+

BehaviorBuilder provides fluent API for constructing instances of a Behavior. +You create an instance of a BehaviorBuilder using the behavior() method on Extent. +All methods except runs() return the same instance of BehaviorBuilder so you can chain multiple optional clauses.

+

Generic type T is the Extent subtype BehaviorBuilder is created with.

+ +
// Create a single behavior with one demand and one supply.
+this.moment1 = this.moment();
+this.moment2 = this.moment();
+this.moment3 = this.moment();
+this.behavior()
+    .demands(this.moment1, this.moment2)
+    .supplies(this.moment3)
+    .runs(ext => {
+        if (ext.moment1.justUpdated || ext.moment2.justUpdatedTo(false)) {
+            ext.moment3.update();
+        }
+    });
+

demands()

+
    +
  • params: ...demands: Demandable[]
  • +
  • returns: BehaviorBuilder<T>
  • +
+

Provide a list of static demands this behavior will link to.

+

dynamicDemands()

+
    +
  • param: switches: Demandable[]
  • +
  • param: links: ((ext: T) => (Demandable | undefined)[] | null)
  • +
  • param: relinkingOrder?: RelinkingOrder
  • +
  • returns: BehaviorBuilder<T>
  • +
+

This clause updates the dynamicDemands of this behavior based on the updating of other resources, the switches. +When the switches update, the links parameter will be called which should return the list of new resources.

+

We permit undefined in the list to make for easier optional chaining. +Returning null is equivalent to setting no dynamicDemands.

+

relinkingOrder parameter can optionally be set to Extent.relinkingOrderSubsequent which will update the demands after the runs block is run.

+ +
// This behavior will automatically demand the deleteButton resource of
+// the currentChild extent whenever it changes.
+this.currentChild = this.state(null);
+this.behavior()
+    .dynamicDemands([this.currentChild], ext => {
+        return [ext.currentChild.value?.deleteButton];
+    })
+    .runs(ext => {
+        if (ext.currentChild.value?.deleteButton.justUpdated) {
+            // do something in response
+        }
+    });
+

dynamicSupplies()

+
    +
  • param: switches: Demandable[]
  • +
  • param: links: ((ext: T) => (Resource | undefined)[] | null)
  • +
  • returns: BehaviorBuilder<T>
  • +
+

This clause updates the dynamicSupplies similarly to the dynamicDemands clause.

+

runs()

+
    +
  • param: block: (ext: T) => void
  • +
  • returns: Behavior
  • +
+

This clause sets the block of code which will run when the behavior is activated. +The parameter ext will be the instance of the Extent this behavior was created on.

+

runs() will return the created behavior which will typically be ignored.

+

supplies()

+
    +
  • params: ...supplies: Resource[]
  • +
  • returns: BehaviorBuilder<T>
  • +
+

Provide a list of static supplies this behavior will link to.

+

Extent

+

Extents are collections of resources and behaviors. +You will create your own Extent subclasses to define your Behavior Graph functionality.

+ +
// Define extent that toggles state on a switch
+class MyExtent extends Extent {
+    constructor(graph) {
+        super(graph);
+
+        this.toggleSwitch = this.moment();
+        this.currentState = this.state(false);
+
+        this.behavior()
+            .demands(this.toggleSwitch)
+            .supplies(this.currentState)
+            .runs(ext => {
+                this.currentState.update(!this.currentState.value);
+            });
+    }
+}
+
+// Create instance of MyExtent and add it to the graph
+let myGraph = new Graph();
+let main = new MyExtent(myGraph);
+main.addToGraphWithAction();
+

action()

+
    +
  • param action: (ext: this) => void
  • +
  • param debugName?: string
  • +
+

Calls the action() method on the underlying Graph object. +Contains an additional ext parameter which will be this Extent instance.

+

async actionAsync()

+
    +
  • param action: (ext: this) => void
  • +
  • param debugName?: string
  • +
  • returns: Promise
  • +
+

Calls the actionAsync() method on the underlying Graph object. +Contains an additional ext parameter which will be this Extent instance.

+

addChildLifetime()

+
    +
  • param: extent: Extent
  • +
+

Adds the parameter to list of child lifetimes. +An extent with child lifetimes is guaranteed to be part of the graph while the child is. +Behaviors in child extents are permitted to have static links to resources in the parent.

+

addedToGraph

+
    +
  • returns State<boolean>
  • +
  • read only property
  • +
+

Every extent comes with this state resource. +It updates to true when the extent is added to the graph.

+

addedToGraphWhen

+
    +
  • returns number | null
  • +
  • read only property
  • +
+

The sequence number of the event the Extent was added to the Graph. +It is null if it has not been added or once it is removed.

+

addToGraph()

+

Adds this extent to the graph. +Behavior Graph will only interact with resources and behaviors after their extent has been added.

+

addToGraphWithAction()

+
    +
  • param: debugName?: string
  • +
+

Syntactic sugar for creating a new action and calling addToGraph(). +debugName is passed to the action.

+

behavior()

+

Creates a BehaviorBuilder instance.

+

debugName

+
    +
  • returns string | null
  • +
  • read write property
  • +
+

You can define a runtime debugName for your instances to aid in debugging. +It defaults to the name of your Extent subclass.

+

new Extent()

+
    +
  • param: graph: Graph
  • +
  • constructor
  • +
+

An Extent must be initialized with a Graph. +You must call super() with the graph in your overridden constructor.

+

graph

+
    +
  • returns Graph
  • +
  • read only property
  • +
+

The graph on which this extent was created.

+

moment<T>()

+
    +
  • param debugName?: string
  • +
+

Factory method to create a moment resource. +By default the debugName will be the name of the property that points to this resource.

+

removeFromGraph()

+
    +
  • param strategy?: ExtentRemoveStrategy
  • +
+

After an extent is removed from the graph its resource and behaviors will no longer interact with other extents in the graph.

+

Extents must be removed in a manner that is consistent with their lifetimes.

+
    +
  • All extents with a unified lifetime must be removed during the same event.
  • +
  • All extents that have a parent lifetime must not remain in the graph longer than their parent.
  • +
+

Providing Extent.removeContainedLifetimes as the strategy parameter will automatically remove all extents with the unified or child lifetimes.

+

removeFromGraphWithAction()

+
    +
  • param: strategy?: ExtentRemoveStrategy
  • +
  • param: debugName?: string
  • +
+

Syntactic sugar for creating a new action and calling removeFromGraph(). +debugName is passed to the action.

+

resource()

+
    +
  • param debugName?: string
  • +
+

Factory method to create a resource. +By default the debugName will be the name of the property that points to this resource.

+

sideEffect()

+
    +
  • param block: (ext: this) => void
  • +
  • param debugName?: string
  • +
+

Calls the sideEffect() method on the underlying Graph object. +Contains an additional ext parameter

+

state<T>()

+
    +
  • param initialState: T
  • +
  • param debugName?: string
  • +
+

Factory method to create a state resource. +By default the debugName will be the name of the property that points to this resource.

+

unifyLifetime()

+
    +
  • param: extent: Extent
  • +
+

Combines the lifetime of this extent with that of the parameter. +Extents with unified lifetimes are guaranteed to be part of the graph for the same period of time. +They are permitted to have static links between them.

+

Graph

+

action()

+
    +
  • param block: () => void
  • +
  • param debugName?: string
  • +
+

Creates a synchronous action on the graph. +By default the debugName will be derived from the set of resources that are updated inside the action block.

+

async actionAsync()

+
    +
  • param block: () => void
  • +
  • param debugName?: string
  • +
  • returns: Promise
  • +
+

Creates an action that will run asynchronously.

+

currentBehavior

+
    +
  • returns Behavior | null
  • +
  • read only property
  • +
+

Returns the currently running behavior or null if otherwise.

+

currentEvent

+
    +
  • returns GraphEvent | null
  • +
  • read only property
  • +
+

Returns the current GraphEvent if the graph is running an event or null otherwise.

+

dateProvider

+
    +
  • returns: GraphDateProvider
  • +
  • read write property
  • +
+

The default dateProvider returns Date.now() which is the source of timestamp on GraphEvent instances. +Overriding is primarily useful for controlling values during testing.

+

debugCycleForBehavior()

+
    +
  • param behavior: Behavior
  • +
  • returns: Resource[]
  • +
+

Used during debugging as an aid when there are dependency cycles. +The returned array contains the sequence of Resource objects which will result in a dependency cycle including this behavior. +The array will be empty if there is not a cycle.

+

lastEvent

+
    +
  • returns GraphEvent
  • +
  • read only property
  • +
+

Returns the last GraphEvent that completed. +It starts as GraphEvent.initialEvent.

+

sideEffect()

+
    +
  • param: block: () => void
  • +
  • param: debugName?: string
  • +
+

Creates a block of code that will run during the side effect phase of the event.

+

GraphEvent

+

sequence

+
    +
  • returns: number
  • +
  • read only property
  • +
+

Each GraphEvent is assigned a monotonically increasing number for each event run on the graph. +You can use this information to quickly determine the order resources update.

+

timestamp

+
    +
  • returns: Date
  • +
  • read only property
  • +
+

Each GraphEvent is given a timestamp according to the registered DateProvider given to a graph instance. +It defaults to Date.now().

+

Moment

+

extends Resource

+

A Moment is a type of Resource for tracking information that exists at a moment in time. +Button presses or network call returns are examples of Moments.

+

Moments optionally have values associated with them. +The payload of a network call return is a possible value for a moment. +Those values are reset to undefined at the end of the event.

+

event

+
    +
  • returns GraphEvent | null
  • +
  • read only property
  • +
+

Returns the GraphEvent of the most recent time the moment was updated. +It is null if it has never been updated.

+

justUpdated

+
    +
  • returns: boolean
  • +
  • read only property
  • +
+

Returns true if the moment updated during this event.

+

justUpdatedTo()

+
    +
  • param value: T
  • +
  • returns boolean
  • +
+

Returns true if the moment was justUpdated and the value == the parameter. +If you wish to use something different than == you can implement your own check as this method is syntactic sugar.

+

update()

+
    +
  • param value: T | undefined
  • +
+

Marks the moment as justUpdated. +If a value is provided, it will be set on the moment for reading.

+

updateWithAction()

+
    +
  • param value: T | undefined
  • +
  • param debugName? : string
  • +
+

Syntactic sugar for calling action() on the underlying graph and calling update() on the moment.

+

value

+
    +
  • returns T
  • +
  • read only property
  • +
+

Returns the value stored in the moment if it was updated during this event. +It is undefined if it was not updated or outside of an event.

+

Moments do not necessarily have a value. +They will not if they were not given one in their update() method.

+

Resource

+

The base class for State and Moment. +Prefer those types in almost all circumstances. +Wherever you see “resource” in this document, assume we are referring to instances of State and Moment.

+

Resource has minimal functionality. +Using instances of this base class directly is useful when forcing a certain ordering relationship between behaviors.

+

debugName

+
    +
  • returns string | null
  • +
  • read write property
  • +
+

Assignable name for use during debugging.

+

extent

+
    +
  • returns Extent
  • +
  • read only property
  • +
+

All resources belong to an Extent.

+

graph

+
    +
  • returns Graph
  • +
  • read only property
  • +
+

All resources belong to a Graph.

+

order

+
    +
  • returns Demandable
  • +
  • read only property
  • +
+

A behavior can also demand resource.order which tells the behavior not to activate when the resource updates.

+

suppliedBy

+
    +
  • returns Behavior | null
  • +
  • read only property
  • +
+

If the resource is supplied by a behavior it will be returned, null otherwise.

+

State

+

extends Resource

+

A State is a type of resource for storing information over a period of time. +Its value will persist into the future until it is updated.

+

All States must be given an initial value when created.

+

event

+
    +
  • returns GraphEvent
  • +
  • read only property
  • +
+

The last time the State was updated. +Will return GraphEvent.initialEvent for its initial value before it has been updated.

+

justUpdated

+
    +
  • returns boolean
  • +
  • read only property
  • +
+

Returns true if the state was updated during this event.

+

justUpdatedTo()

+
    +
  • param: toState: T
  • +
  • returns: boolean
  • +
+

Returns true if the state was updated during this event and toState parameter == value.

+

justUpdatedFrom()

+
    +
  • param: fromState: T
  • +
  • returns: boolean
  • +
+

Returns true if the state was updated during this event and the fromState parameter == the value it had before updating.

+

justUpdatedToFrom()

+
    +
  • param: toState: T
  • +
  • param: fromState: T
  • +
  • returns: boolean
  • +
+

A combination of justUpdatedTo() and justUpdatedFrom()

+

traceEvent

+
    +
  • returns: GraphEvent
  • +
  • read only property
  • +
+

What was the value of the event property at the beginning of the current event.

+

traceValue

+
    +
  • returns: T
  • +
  • read only property
  • +
+

What was the value of the value property at the beginning of the current event.

+

updateWithAction()

+
    +
  • param: newValue: T
  • +
  • param: debugName?: string
  • +
+

Equivalent to calling action() on the underlying Graph instance and update() on the State object.

+

update()

+
    +
  • param: newValue: T
  • +
+

Checks to see if the newValue parameter !== the current value, and if so updates it to that new value.

+

updateForce()

+
    +
  • param: newValue: T
  • +
+

Updates value to the newValue even if they are the same.

+

value

+
    +
  • returns: T
  • +
  • read only property
  • +
+

The current underlying value.

+

Interfaces

+

Demandable

+

What a behavior can demand. A sealed opaque type which includes:

+
    +
  • Instances of Resource and its subclasses State and Moment
  • +
  • The object returned by .order on an instance of Resource
  • +
+

There are no other Demandable types and it is not open for extension.

+

DateProvider

+

Optional override for default dateProvier on Graph instance.

+

Implement a type with a single method:

+

now(): Date

+ + + + +
+ + +
+
+
+ +
+
+
+
+ +
+
+ +
+
+ © 2022 Yahoo All Rights Reserved + + + + +
+
+
+
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/typescript/categories/index.html b/docs/typescript/categories/index.html new file mode 100644 index 0000000..a04a16f --- /dev/null +++ b/docs/typescript/categories/index.html @@ -0,0 +1,143 @@ + + + + + + + + + + + + + + + + + + + + + +Categories | Behavior Graph + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+
+
+ +
+
+

Categories

+ + + + + + + +
+
+ +
+ +
+
+
+
+ +
+
+ +
+
+ © 2022 Yahoo All Rights Reserved + + + + +
+
+
+
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/typescript/categories/index.xml b/docs/typescript/categories/index.xml new file mode 100644 index 0000000..e920aa4 --- /dev/null +++ b/docs/typescript/categories/index.xml @@ -0,0 +1,17 @@ + + + Behavior Graph – Categories + https://yahoo.github.io/bgdocs/docs/typescript/categories/ + Recent content in Categories on Behavior Graph + Hugo -- gohugo.io + + + + + + + + + + + diff --git a/docs/typescript/code-example/index.html b/docs/typescript/code-example/index.html new file mode 100644 index 0000000..6f0dba6 --- /dev/null +++ b/docs/typescript/code-example/index.html @@ -0,0 +1,367 @@ + + + + + + + + + + + + + + + + + + + + +Code Example | Behavior Graph + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+
+
+
+ + +
+ + + + + +
+

Code Example

+ + +

We can illustrate how Behavior Graph code works in more detail through another example application, a typical login screen. +This is just a walkthrough, please use the tutorials for a complete guide to learning Behavior Graph.

+

Login Page

+

As a first feature, we would like the Login button to remain disabled until the user has entered both a reasonable email and password. +If the user types in some password but an invalid email address (missing the ‘@’ character, for example) the Login button will remain disabled. +Once she corrects the email address by adding an ‘@’ character, the Login button should immediately enable.

+

In Behavior Graph, this unit of functionality constitutes a typical behavior. +It looks like this

+
this.behavior()
+    .supplies(this.loginEnabled)
+    .demands(this.email, this.password)
+    .runs(() => {
+        const emailValid = this.validEmailAddress(this.email.value);
+        const passwordValid = this.password.value.length > 0;
+        const enabled = emailValid && passwordValid;
+        this.loginEnabled.update(enabled);
+    });
+

Behaviors have dependencies on units of information called resources. +This behavior depends on two resources, email and password. +They appear as parameter of the demands() clause of behavior(). +This list is called the behavior’s demands. +Our behavior has read only access to these resources.

+

As stated before, behaviors are never called directly. +In specifying a behavior’s demands, we are saying, “whenever any of these resources updates (changes), then this behavior needs to run”. +In our example, when either email or password (or both) update, this behavior will run in response.

+

email and password are a specific type of resource called a state resource which is designed for saving and retrieving information. +The contents of these state resources are available via their value property.

+

The block of code specified in the behavior is the code that will run. +A typical behavior uses normal code to perform its work. +Here we check the validity of the email with a normal function. +We determine if the Login button should be enabled using normal Boolean logic.

+

This behavior is responsible for the enabled state of the Login button. +This information is stored in another state resource called loginEnabled. +We specify a behavior’s responsibilities in the supplies() clause of behavior(). +This list is called the behavior’s supplies. +A behavior can read and write the contents of its supplies. +The contents of a state resource can be written to by calling its update method.

+

We can continue to develop our Login page by adding a second feature. +When the user clicks the Login button and we are not already logging in, then we would like to enter into a logging in state. +In order to prevent mistakes, when we are in a logging in state, we would also like the Login button to be disabled.

+

To implement this new feature we introduce a second behavior and make a small change to our existing behavior.

+
this.behavior()
+    .supplies(this.loggingIn)
+    .demands(this.loginClick)
+    .runs(() => {
+        if (this.loginClick.justUpdated && !this.loggingIn.value) {
+            this.loggingIn.update(true);
+        }
+    });
+
+this.behavior()
+    .supplies(this.loginEnabled)
+    .demands(this.email, this.password, this.loggingIn)
+    .runs(() => {
+        const emailValid = this.validEmailAddress(this.email.value);
+        const passwordValid = this.password.value.length > 0;
+        const enabled = emailValid && passwordValid & !this.loggingIn.value;
+        this.loginEnabled.update(enabled);
+    })
+

The new behavior has one demand, loginClick. +This is a second type of resource called a moment resource. +Moments are designed to track momentary happenings such as a button click or network call returning. +We can check if a moment has just happened by accessing its justUpdated property.

+

When the user clicks on the button, loginClick will update, and this new behavior will run. +It performs a simple Boolean check to determine if the loggingIn state resource needs to update to true. +It is allowed to update this resource because loggingIn is part of its supplies.

+

We also modified our previous behavior to include loggingIn as one of its demands. +This means it will run when the loggingIn resource updates as well as have permission to access the Boolean value of loggingIn. +Now the state of loginEnabled depends on all three pieces of information: email, password, and loggingIn.

+

Actions

+

Login Behavior Graph

+

Information comes into our system via actions. +A typical UI library will provide some type of callback or event system to capture user inputs. +In this example we will listen to a click handler to create a new action which updates the loginClick moment resource.

+
this.loginButton.onClick = () => {
+    this.action(() => {
+        this.loginClick.update();
+    });
+};
+

We would similarly connect email and password to their respective text fields.

+

Once the user has entered a valid email and password, the Login button will enable. +When the user subsequently clicks on the Login button, the behavior that supplies loggingIn will run. +It will update the loggingIn resource to true. +This in turn will cause the behavior that supplies loginEnabled behavior to run. +It will update the loginEnabled resource to false.

+

Side Effects

+

In order to perform real output to the UI library, we need to create a side effect.

+
this.behavior()
+    .supplies(this.loginEnabled)
+    .demands(this.email, this.password, this.loggingIn)
+    .runs(() => {
+        const emailValid = this.validEmailAddress(this.email.value);
+        const passwordValid = this.password.value.length > 0;
+        const enabled = emailValid && passwordValid & !this.loggingIn.value;
+        this.loginEnabled.update(enabled);
+
+        this.sideEffect(() => {
+            this.loginButton.enabled = this.loginEnabled.value;
+        });
+    })
+

Side effects are created directly inside behaviors. +This side effect updates the enabled state of the loginButton based on the state of the loginEnabled resource. +It does not run immediately, however. +Behavior Graph defers the running of side effects until after all behaviors have run. +Side effects are a practical way for Behavior Graph to create output while ensuring access to consistent state.

+

This example covers the primary concepts when developing with Behavior Graph. +There are, however, additional features that make Behavior Graph a practical software library. +Please work through the tutorials for a full coverage of the core features.

+ + + + +
+ + +
+
+
+ +
+
+
+
+ +
+
+ +
+
+ © 2022 Yahoo All Rights Reserved + + + + +
+
+
+
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/typescript/css/prism.css b/docs/typescript/css/prism.css new file mode 100644 index 0000000..f55c4c6 --- /dev/null +++ b/docs/typescript/css/prism.css @@ -0,0 +1,208 @@ +/* PrismJS 1.21.0 +https://prismjs.com/download.html#themes=prism&languages=markup+css+clike+javascript+bash+c+csharp+cpp+go+java+markdown+python+scss+sql+toml+yaml&plugins=toolbar+copy-to-clipboard */ +/** + * prism.js default theme for JavaScript, CSS and HTML + * Based on dabblet (http://dabblet.com) + * @author Lea Verou + */ + +code[class*="language-"], +pre[class*="language-"] { + color: black; + background: none; + text-shadow: 0 1px white; + font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace; + font-size: 1em; + text-align: left; + white-space: pre; + word-spacing: normal; + word-break: normal; + word-wrap: normal; + line-height: 1.5; + + -moz-tab-size: 4; + -o-tab-size: 4; + tab-size: 4; + + -webkit-hyphens: none; + -moz-hyphens: none; + -ms-hyphens: none; + hyphens: none; +} + +pre[class*="language-"]::-moz-selection, pre[class*="language-"] ::-moz-selection, +code[class*="language-"]::-moz-selection, code[class*="language-"] ::-moz-selection { + text-shadow: none; + background: #b3d4fc; +} + +pre[class*="language-"]::selection, pre[class*="language-"] ::selection, +code[class*="language-"]::selection, code[class*="language-"] ::selection { + text-shadow: none; + background: #b3d4fc; +} + +@media print { + code[class*="language-"], + pre[class*="language-"] { + text-shadow: none; + } +} + +/* Code blocks */ +pre[class*="language-"] { + padding: 1em; + margin: .5em 0; + overflow: auto; +} + +:not(pre) > code[class*="language-"], +pre[class*="language-"] { + background: #f5f2f0; +} + +/* Inline code */ +:not(pre) > code[class*="language-"] { + padding: .1em; + border-radius: .3em; + white-space: normal; +} + +.token.comment, +.token.prolog, +.token.doctype, +.token.cdata { + color: slategray; +} + +.token.punctuation { + color: #999; +} + +.token.namespace { + opacity: .7; +} + +.token.property, +.token.tag, +.token.boolean, +.token.number, +.token.constant, +.token.symbol, +.token.deleted { + color: #905; +} + +.token.selector, +.token.attr-name, +.token.string, +.token.char, +.token.builtin, +.token.inserted { + color: #690; +} + +.token.operator, +.token.entity, +.token.url, +.language-css .token.string, +.style .token.string { + color: #9a6e3a; + /* This background color was intended by the author of this theme. */ + background: hsla(0, 0%, 100%, .5); +} + +.token.atrule, +.token.attr-value, +.token.keyword { + color: #07a; +} + +.token.function, +.token.class-name { + color: #DD4A68; +} + +.token.regex, +.token.important, +.token.variable { + color: #e90; +} + +.token.important, +.token.bold { + font-weight: bold; +} +.token.italic { + font-style: italic; +} + +.token.entity { + cursor: help; +} + +div.code-toolbar { + position: relative; +} + +div.code-toolbar > .toolbar { + position: absolute; + top: .3em; + right: .2em; + transition: opacity 0.3s ease-in-out; + opacity: 0; +} + +div.code-toolbar:hover > .toolbar { + opacity: 1; +} + +/* Separate line b/c rules are thrown out if selector is invalid. + IE11 and old Edge versions don't support :focus-within. */ +div.code-toolbar:focus-within > .toolbar { + opacity: 1; +} + +div.code-toolbar > .toolbar .toolbar-item { + display: inline-block; +} + +div.code-toolbar > .toolbar a { + cursor: pointer; +} + +div.code-toolbar > .toolbar button { + background: none; + border: 0; + color: inherit; + font: inherit; + line-height: normal; + overflow: visible; + padding: 0; + -webkit-user-select: none; /* for button */ + -moz-user-select: none; + -ms-user-select: none; +} + +div.code-toolbar > .toolbar a, +div.code-toolbar > .toolbar button, +div.code-toolbar > .toolbar span { + color: #bbb; + font-size: .8em; + padding: 0 .5em; + background: #f5f2f0; + background: rgba(224, 224, 224, 0.2); + box-shadow: 0 2px 0 0 rgba(0,0,0,0.2); + border-radius: .5em; +} + +div.code-toolbar > .toolbar a:hover, +div.code-toolbar > .toolbar a:focus, +div.code-toolbar > .toolbar button:hover, +div.code-toolbar > .toolbar button:focus, +div.code-toolbar > .toolbar span:hover, +div.code-toolbar > .toolbar span:focus { + color: inherit; + text-decoration: none; +} + diff --git a/docs/typescript/css/shortcodes.css b/docs/typescript/css/shortcodes.css new file mode 100644 index 0000000..0aa1c0f --- /dev/null +++ b/docs/typescript/css/shortcodes.css @@ -0,0 +1,2 @@ +@import "shortcodes/tabbed-pane.css"; +@import "shortcodes/cards-pane.css"; diff --git a/docs/typescript/css/shortcodes/cards-pane.css b/docs/typescript/css/shortcodes/cards-pane.css new file mode 100644 index 0000000..34c8545 --- /dev/null +++ b/docs/typescript/css/shortcodes/cards-pane.css @@ -0,0 +1,21 @@ +.card-deck { + max-width: 83%; +} + +.card { + max-width: 80%; +} + +.card-body.code { + background-color: #f8f9fa; + padding: 0 0 0 1ex; +} + +.card-body pre { + margin: 0; + padding: 0 1rem 1rem 1rem; +} + +.card .highlight { + border: none; +} diff --git a/docs/typescript/css/shortcodes/tabbed-pane.css b/docs/typescript/css/shortcodes/tabbed-pane.css new file mode 100644 index 0000000..3016398 --- /dev/null +++ b/docs/typescript/css/shortcodes/tabbed-pane.css @@ -0,0 +1,18 @@ +.td-content .highlight { + margin: 0rem 0 2rem 0; +} + +.tab-content .highlight { + border: none; +} + +.tab-content { + margin: 0rem; + max-width: 80%; +} + +.tab-content pre { + border-left: 1px solid rgba(0, 0, 0, 0.125); + border-right: 1px solid rgba(0, 0, 0, 0.125); + border-bottom: 1px solid rgba(0, 0, 0, 0.125); +} diff --git a/docs/typescript/css/swagger-ui.css b/docs/typescript/css/swagger-ui.css new file mode 100644 index 0000000..c61e5a8 --- /dev/null +++ b/docs/typescript/css/swagger-ui.css @@ -0,0 +1,4 @@ +.swagger-ui{ + /*! normalize.css v7.0.0 | MIT License | github.com/necolas/normalize.css */font-family:sans-serif;color:#3b4151}.swagger-ui html{line-height:1.15;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}.swagger-ui body{margin:0}.swagger-ui article,.swagger-ui aside,.swagger-ui footer,.swagger-ui header,.swagger-ui nav,.swagger-ui section{display:block}.swagger-ui h1{font-size:2em;margin:.67em 0}.swagger-ui figcaption,.swagger-ui figure,.swagger-ui main{display:block}.swagger-ui figure{margin:1em 40px}.swagger-ui hr{box-sizing:content-box;height:0;overflow:visible}.swagger-ui pre{font-family:monospace,monospace;font-size:1em}.swagger-ui a{background-color:transparent;-webkit-text-decoration-skip:objects}.swagger-ui abbr[title]{border-bottom:none;text-decoration:underline;-webkit-text-decoration:underline dotted;text-decoration:underline dotted}.swagger-ui b,.swagger-ui strong{font-weight:inherit;font-weight:bolder}.swagger-ui code,.swagger-ui kbd,.swagger-ui samp{font-family:monospace,monospace;font-size:1em}.swagger-ui dfn{font-style:italic}.swagger-ui mark{background-color:#ff0;color:#000}.swagger-ui small{font-size:80%}.swagger-ui sub,.swagger-ui sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}.swagger-ui sub{bottom:-.25em}.swagger-ui sup{top:-.5em}.swagger-ui audio,.swagger-ui video{display:inline-block}.swagger-ui audio:not([controls]){display:none;height:0}.swagger-ui img{border-style:none}.swagger-ui svg:not(:root){overflow:hidden}.swagger-ui button,.swagger-ui input,.swagger-ui optgroup,.swagger-ui select,.swagger-ui textarea{font-family:sans-serif;font-size:100%;line-height:1.15;margin:0}.swagger-ui button,.swagger-ui input{overflow:visible}.swagger-ui button,.swagger-ui select{text-transform:none}.swagger-ui [type=reset],.swagger-ui [type=submit],.swagger-ui button,.swagger-ui html [type=button]{-webkit-appearance:button}.swagger-ui [type=button]::-moz-focus-inner,.swagger-ui [type=reset]::-moz-focus-inner,.swagger-ui [type=submit]::-moz-focus-inner,.swagger-ui button::-moz-focus-inner{border-style:none;padding:0}.swagger-ui [type=button]:-moz-focusring,.swagger-ui [type=reset]:-moz-focusring,.swagger-ui [type=submit]:-moz-focusring,.swagger-ui button:-moz-focusring{outline:1px dotted ButtonText}.swagger-ui fieldset{padding:.35em .75em .625em}.swagger-ui legend{box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal}.swagger-ui progress{display:inline-block;vertical-align:baseline}.swagger-ui textarea{overflow:auto}.swagger-ui [type=checkbox],.swagger-ui [type=radio]{box-sizing:border-box;padding:0}.swagger-ui [type=number]::-webkit-inner-spin-button,.swagger-ui [type=number]::-webkit-outer-spin-button{height:auto}.swagger-ui [type=search]{-webkit-appearance:textfield;outline-offset:-2px}.swagger-ui [type=search]::-webkit-search-cancel-button,.swagger-ui [type=search]::-webkit-search-decoration{-webkit-appearance:none}.swagger-ui ::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}.swagger-ui details,.swagger-ui menu{display:block}.swagger-ui summary{display:list-item}.swagger-ui canvas{display:inline-block}.swagger-ui template{display:none}.swagger-ui [hidden]{display:none}.swagger-ui .debug *{outline:1px solid gold}.swagger-ui .debug-white *{outline:1px solid #fff}.swagger-ui .debug-black *{outline:1px solid #000}.swagger-ui .debug-grid{background:transparent url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAYAAADED76LAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyhpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNi1jMTExIDc5LjE1ODMyNSwgMjAxNS8wOS8xMC0wMToxMDoyMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6MTRDOTY4N0U2N0VFMTFFNjg2MzZDQjkwNkQ4MjgwMEIiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6MTRDOTY4N0Q2N0VFMTFFNjg2MzZDQjkwNkQ4MjgwMEIiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTUgKE1hY2ludG9zaCkiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo3NjcyQkQ3NjY3QzUxMUU2QjJCQ0UyNDA4MTAwMjE3MSIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo3NjcyQkQ3NzY3QzUxMUU2QjJCQ0UyNDA4MTAwMjE3MSIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PsBS+GMAAAAjSURBVHjaYvz//z8DLsD4gcGXiYEAGBIKGBne//fFpwAgwAB98AaF2pjlUQAAAABJRU5ErkJggg==) repeat 0 0}.swagger-ui .debug-grid-16{background:transparent url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyhpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNi1jMTExIDc5LjE1ODMyNSwgMjAxNS8wOS8xMC0wMToxMDoyMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6ODYyRjhERDU2N0YyMTFFNjg2MzZDQjkwNkQ4MjgwMEIiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6ODYyRjhERDQ2N0YyMTFFNjg2MzZDQjkwNkQ4MjgwMEIiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTUgKE1hY2ludG9zaCkiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo3NjcyQkQ3QTY3QzUxMUU2QjJCQ0UyNDA4MTAwMjE3MSIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo3NjcyQkQ3QjY3QzUxMUU2QjJCQ0UyNDA4MTAwMjE3MSIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PvCS01IAAABMSURBVHjaYmR4/5+BFPBfAMFm/MBgx8RAGWCn1AAmSg34Q6kBDKMGMDCwICeMIemF/5QawEipAWwUhwEjMDvbAWlWkvVBwu8vQIABAEwBCph8U6c0AAAAAElFTkSuQmCC) repeat 0 0}.swagger-ui .debug-grid-8-solid{background:#fff url(data:image/jpeg;base64,/9j/4QAYRXhpZgAASUkqAAgAAAAAAAAAAAAAAP/sABFEdWNreQABAAQAAAAAAAD/4QMxaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLwA8P3hwYWNrZXQgYmVnaW49Iu+7vyIgaWQ9Ilc1TTBNcENlaGlIenJlU3pOVGN6a2M5ZCI/PiA8eDp4bXBtZXRhIHhtbG5zOng9ImFkb2JlOm5zOm1ldGEvIiB4OnhtcHRrPSJBZG9iZSBYTVAgQ29yZSA1LjYtYzExMSA3OS4xNTgzMjUsIDIwMTUvMDkvMTAtMDE6MTA6MjAgICAgICAgICI+IDxyZGY6UkRGIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyI+IDxyZGY6RGVzY3JpcHRpb24gcmRmOmFib3V0PSIiIHhtbG5zOnhtcD0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLyIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bXA6Q3JlYXRvclRvb2w9IkFkb2JlIFBob3Rvc2hvcCBDQyAyMDE1IChNYWNpbnRvc2gpIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOkIxMjI0OTczNjdCMzExRTZCMkJDRTI0MDgxMDAyMTcxIiB4bXBNTTpEb2N1bWVudElEPSJ4bXAuZGlkOkIxMjI0OTc0NjdCMzExRTZCMkJDRTI0MDgxMDAyMTcxIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6QjEyMjQ5NzE2N0IzMTFFNkIyQkNFMjQwODEwMDIxNzEiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6QjEyMjQ5NzI2N0IzMTFFNkIyQkNFMjQwODEwMDIxNzEiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz7/7gAOQWRvYmUAZMAAAAAB/9sAhAAbGhopHSlBJiZBQi8vL0JHPz4+P0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHAR0pKTQmND8oKD9HPzU/R0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0f/wAARCAAIAAgDASIAAhEBAxEB/8QAWQABAQAAAAAAAAAAAAAAAAAAAAYBAQEAAAAAAAAAAAAAAAAAAAIEEAEBAAMBAAAAAAAAAAAAAAABADECA0ERAAEDBQAAAAAAAAAAAAAAAAARITFBUWESIv/aAAwDAQACEQMRAD8AoOnTV1QTD7JJshP3vSM3P//Z) repeat 0 0}.swagger-ui .debug-grid-16-solid{background:#fff url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyhpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNi1jMTExIDc5LjE1ODMyNSwgMjAxNS8wOS8xMC0wMToxMDoyMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTUgKE1hY2ludG9zaCkiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6NzY3MkJEN0U2N0M1MTFFNkIyQkNFMjQwODEwMDIxNzEiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6NzY3MkJEN0Y2N0M1MTFFNkIyQkNFMjQwODEwMDIxNzEiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo3NjcyQkQ3QzY3QzUxMUU2QjJCQ0UyNDA4MTAwMjE3MSIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo3NjcyQkQ3RDY3QzUxMUU2QjJCQ0UyNDA4MTAwMjE3MSIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/Pve6J3kAAAAzSURBVHjaYvz//z8D0UDsMwMjSRoYP5Gq4SPNbRjVMEQ1fCRDg+in/6+J1AJUxsgAEGAA31BAJMS0GYEAAAAASUVORK5CYII=) repeat 0 0}.swagger-ui .border-box,.swagger-ui a,.swagger-ui article,.swagger-ui body,.swagger-ui code,.swagger-ui dd,.swagger-ui div,.swagger-ui dl,.swagger-ui dt,.swagger-ui fieldset,.swagger-ui footer,.swagger-ui form,.swagger-ui h1,.swagger-ui h2,.swagger-ui h3,.swagger-ui h4,.swagger-ui h5,.swagger-ui h6,.swagger-ui header,.swagger-ui html,.swagger-ui input[type=email],.swagger-ui input[type=number],.swagger-ui input[type=password],.swagger-ui input[type=tel],.swagger-ui input[type=text],.swagger-ui input[type=url],.swagger-ui legend,.swagger-ui li,.swagger-ui main,.swagger-ui ol,.swagger-ui p,.swagger-ui pre,.swagger-ui section,.swagger-ui table,.swagger-ui td,.swagger-ui textarea,.swagger-ui th,.swagger-ui tr,.swagger-ui ul{box-sizing:border-box}.swagger-ui .aspect-ratio{height:0;position:relative}.swagger-ui .aspect-ratio--16x9{padding-bottom:56.25%}.swagger-ui .aspect-ratio--9x16{padding-bottom:177.77%}.swagger-ui .aspect-ratio--4x3{padding-bottom:75%}.swagger-ui .aspect-ratio--3x4{padding-bottom:133.33%}.swagger-ui .aspect-ratio--6x4{padding-bottom:66.6%}.swagger-ui .aspect-ratio--4x6{padding-bottom:150%}.swagger-ui .aspect-ratio--8x5{padding-bottom:62.5%}.swagger-ui .aspect-ratio--5x8{padding-bottom:160%}.swagger-ui .aspect-ratio--7x5{padding-bottom:71.42%}.swagger-ui .aspect-ratio--5x7{padding-bottom:140%}.swagger-ui .aspect-ratio--1x1{padding-bottom:100%}.swagger-ui .aspect-ratio--object{position:absolute;top:0;right:0;bottom:0;left:0;width:100%;height:100%;z-index:100}@media screen and (min-width:30em){.swagger-ui .aspect-ratio-ns{height:0;position:relative}.swagger-ui .aspect-ratio--16x9-ns{padding-bottom:56.25%}.swagger-ui .aspect-ratio--9x16-ns{padding-bottom:177.77%}.swagger-ui .aspect-ratio--4x3-ns{padding-bottom:75%}.swagger-ui .aspect-ratio--3x4-ns{padding-bottom:133.33%}.swagger-ui .aspect-ratio--6x4-ns{padding-bottom:66.6%}.swagger-ui .aspect-ratio--4x6-ns{padding-bottom:150%}.swagger-ui .aspect-ratio--8x5-ns{padding-bottom:62.5%}.swagger-ui .aspect-ratio--5x8-ns{padding-bottom:160%}.swagger-ui .aspect-ratio--7x5-ns{padding-bottom:71.42%}.swagger-ui .aspect-ratio--5x7-ns{padding-bottom:140%}.swagger-ui .aspect-ratio--1x1-ns{padding-bottom:100%}.swagger-ui .aspect-ratio--object-ns{position:absolute;top:0;right:0;bottom:0;left:0;width:100%;height:100%;z-index:100}}@media screen and (min-width:30em) and (max-width:60em){.swagger-ui .aspect-ratio-m{height:0;position:relative}.swagger-ui .aspect-ratio--16x9-m{padding-bottom:56.25%}.swagger-ui .aspect-ratio--9x16-m{padding-bottom:177.77%}.swagger-ui .aspect-ratio--4x3-m{padding-bottom:75%}.swagger-ui .aspect-ratio--3x4-m{padding-bottom:133.33%}.swagger-ui .aspect-ratio--6x4-m{padding-bottom:66.6%}.swagger-ui .aspect-ratio--4x6-m{padding-bottom:150%}.swagger-ui .aspect-ratio--8x5-m{padding-bottom:62.5%}.swagger-ui .aspect-ratio--5x8-m{padding-bottom:160%}.swagger-ui .aspect-ratio--7x5-m{padding-bottom:71.42%}.swagger-ui .aspect-ratio--5x7-m{padding-bottom:140%}.swagger-ui .aspect-ratio--1x1-m{padding-bottom:100%}.swagger-ui .aspect-ratio--object-m{position:absolute;top:0;right:0;bottom:0;left:0;width:100%;height:100%;z-index:100}}@media screen and (min-width:60em){.swagger-ui .aspect-ratio-l{height:0;position:relative}.swagger-ui .aspect-ratio--16x9-l{padding-bottom:56.25%}.swagger-ui .aspect-ratio--9x16-l{padding-bottom:177.77%}.swagger-ui .aspect-ratio--4x3-l{padding-bottom:75%}.swagger-ui .aspect-ratio--3x4-l{padding-bottom:133.33%}.swagger-ui .aspect-ratio--6x4-l{padding-bottom:66.6%}.swagger-ui .aspect-ratio--4x6-l{padding-bottom:150%}.swagger-ui .aspect-ratio--8x5-l{padding-bottom:62.5%}.swagger-ui .aspect-ratio--5x8-l{padding-bottom:160%}.swagger-ui .aspect-ratio--7x5-l{padding-bottom:71.42%}.swagger-ui .aspect-ratio--5x7-l{padding-bottom:140%}.swagger-ui .aspect-ratio--1x1-l{padding-bottom:100%}.swagger-ui .aspect-ratio--object-l{position:absolute;top:0;right:0;bottom:0;left:0;width:100%;height:100%;z-index:100}}.swagger-ui img{max-width:100%}.swagger-ui .cover{background-size:cover!important}.swagger-ui .contain{background-size:contain!important}@media screen and (min-width:30em){.swagger-ui .cover-ns{background-size:cover!important}.swagger-ui .contain-ns{background-size:contain!important}}@media screen and (min-width:30em) and (max-width:60em){.swagger-ui .cover-m{background-size:cover!important}.swagger-ui .contain-m{background-size:contain!important}}@media screen and (min-width:60em){.swagger-ui .cover-l{background-size:cover!important}.swagger-ui .contain-l{background-size:contain!important}}.swagger-ui .bg-center{background-repeat:no-repeat;background-position:50%}.swagger-ui .bg-top{background-repeat:no-repeat;background-position:top}.swagger-ui .bg-right{background-repeat:no-repeat;background-position:100%}.swagger-ui .bg-bottom{background-repeat:no-repeat;background-position:bottom}.swagger-ui .bg-left{background-repeat:no-repeat;background-position:0}@media screen and (min-width:30em){.swagger-ui .bg-center-ns{background-repeat:no-repeat;background-position:50%}.swagger-ui .bg-top-ns{background-repeat:no-repeat;background-position:top}.swagger-ui .bg-right-ns{background-repeat:no-repeat;background-position:100%}.swagger-ui .bg-bottom-ns{background-repeat:no-repeat;background-position:bottom}.swagger-ui .bg-left-ns{background-repeat:no-repeat;background-position:0}}@media screen and (min-width:30em) and (max-width:60em){.swagger-ui .bg-center-m{background-repeat:no-repeat;background-position:50%}.swagger-ui .bg-top-m{background-repeat:no-repeat;background-position:top}.swagger-ui .bg-right-m{background-repeat:no-repeat;background-position:100%}.swagger-ui .bg-bottom-m{background-repeat:no-repeat;background-position:bottom}.swagger-ui .bg-left-m{background-repeat:no-repeat;background-position:0}}@media screen and (min-width:60em){.swagger-ui .bg-center-l{background-repeat:no-repeat;background-position:50%}.swagger-ui .bg-top-l{background-repeat:no-repeat;background-position:top}.swagger-ui .bg-right-l{background-repeat:no-repeat;background-position:100%}.swagger-ui .bg-bottom-l{background-repeat:no-repeat;background-position:bottom}.swagger-ui .bg-left-l{background-repeat:no-repeat;background-position:0}}.swagger-ui .outline{outline:1px solid}.swagger-ui .outline-transparent{outline:1px solid transparent}.swagger-ui .outline-0{outline:0}@media screen and (min-width:30em){.swagger-ui .outline-ns{outline:1px solid}.swagger-ui .outline-transparent-ns{outline:1px solid transparent}.swagger-ui .outline-0-ns{outline:0}}@media screen and (min-width:30em) and (max-width:60em){.swagger-ui .outline-m{outline:1px solid}.swagger-ui .outline-transparent-m{outline:1px solid transparent}.swagger-ui .outline-0-m{outline:0}}@media screen and (min-width:60em){.swagger-ui .outline-l{outline:1px solid}.swagger-ui .outline-transparent-l{outline:1px solid transparent}.swagger-ui .outline-0-l{outline:0}}.swagger-ui .ba{border-style:solid;border-width:1px}.swagger-ui .bt{border-top-style:solid;border-top-width:1px}.swagger-ui .br{border-right-style:solid;border-right-width:1px}.swagger-ui .bb{border-bottom-style:solid;border-bottom-width:1px}.swagger-ui .bl{border-left-style:solid;border-left-width:1px}.swagger-ui .bn{border-style:none;border-width:0}@media screen and (min-width:30em){.swagger-ui .ba-ns{border-style:solid;border-width:1px}.swagger-ui .bt-ns{border-top-style:solid;border-top-width:1px}.swagger-ui .br-ns{border-right-style:solid;border-right-width:1px}.swagger-ui .bb-ns{border-bottom-style:solid;border-bottom-width:1px}.swagger-ui .bl-ns{border-left-style:solid;border-left-width:1px}.swagger-ui .bn-ns{border-style:none;border-width:0}}@media screen and (min-width:30em) and (max-width:60em){.swagger-ui .ba-m{border-style:solid;border-width:1px}.swagger-ui .bt-m{border-top-style:solid;border-top-width:1px}.swagger-ui .br-m{border-right-style:solid;border-right-width:1px}.swagger-ui .bb-m{border-bottom-style:solid;border-bottom-width:1px}.swagger-ui .bl-m{border-left-style:solid;border-left-width:1px}.swagger-ui .bn-m{border-style:none;border-width:0}}@media screen and (min-width:60em){.swagger-ui .ba-l{border-style:solid;border-width:1px}.swagger-ui .bt-l{border-top-style:solid;border-top-width:1px}.swagger-ui .br-l{border-right-style:solid;border-right-width:1px}.swagger-ui .bb-l{border-bottom-style:solid;border-bottom-width:1px}.swagger-ui .bl-l{border-left-style:solid;border-left-width:1px}.swagger-ui .bn-l{border-style:none;border-width:0}}.swagger-ui .b--black{border-color:#000}.swagger-ui .b--near-black{border-color:#111}.swagger-ui .b--dark-gray{border-color:#333}.swagger-ui .b--mid-gray{border-color:#555}.swagger-ui .b--gray{border-color:#777}.swagger-ui .b--silver{border-color:#999}.swagger-ui .b--light-silver{border-color:#aaa}.swagger-ui .b--moon-gray{border-color:#ccc}.swagger-ui .b--light-gray{border-color:#eee}.swagger-ui .b--near-white{border-color:#f4f4f4}.swagger-ui .b--white{border-color:#fff}.swagger-ui .b--white-90{border-color:hsla(0,0%,100%,.9)}.swagger-ui .b--white-80{border-color:hsla(0,0%,100%,.8)}.swagger-ui .b--white-70{border-color:hsla(0,0%,100%,.7)}.swagger-ui .b--white-60{border-color:hsla(0,0%,100%,.6)}.swagger-ui .b--white-50{border-color:hsla(0,0%,100%,.5)}.swagger-ui .b--white-40{border-color:hsla(0,0%,100%,.4)}.swagger-ui .b--white-30{border-color:hsla(0,0%,100%,.3)}.swagger-ui .b--white-20{border-color:hsla(0,0%,100%,.2)}.swagger-ui .b--white-10{border-color:hsla(0,0%,100%,.1)}.swagger-ui .b--white-05{border-color:hsla(0,0%,100%,.05)}.swagger-ui .b--white-025{border-color:hsla(0,0%,100%,.025)}.swagger-ui .b--white-0125{border-color:hsla(0,0%,100%,.0125)}.swagger-ui .b--black-90{border-color:rgba(0,0,0,.9)}.swagger-ui .b--black-80{border-color:rgba(0,0,0,.8)}.swagger-ui .b--black-70{border-color:rgba(0,0,0,.7)}.swagger-ui .b--black-60{border-color:rgba(0,0,0,.6)}.swagger-ui .b--black-50{border-color:rgba(0,0,0,.5)}.swagger-ui .b--black-40{border-color:rgba(0,0,0,.4)}.swagger-ui .b--black-30{border-color:rgba(0,0,0,.3)}.swagger-ui .b--black-20{border-color:rgba(0,0,0,.2)}.swagger-ui .b--black-10{border-color:rgba(0,0,0,.1)}.swagger-ui .b--black-05{border-color:rgba(0,0,0,.05)}.swagger-ui .b--black-025{border-color:rgba(0,0,0,.025)}.swagger-ui .b--black-0125{border-color:rgba(0,0,0,.0125)}.swagger-ui .b--dark-red{border-color:#e7040f}.swagger-ui .b--red{border-color:#ff4136}.swagger-ui .b--light-red{border-color:#ff725c}.swagger-ui .b--orange{border-color:#ff6300}.swagger-ui .b--gold{border-color:#ffb700}.swagger-ui .b--yellow{border-color:gold}.swagger-ui .b--light-yellow{border-color:#fbf1a9}.swagger-ui .b--purple{border-color:#5e2ca5}.swagger-ui .b--light-purple{border-color:#a463f2}.swagger-ui .b--dark-pink{border-color:#d5008f}.swagger-ui .b--hot-pink{border-color:#ff41b4}.swagger-ui .b--pink{border-color:#ff80cc}.swagger-ui .b--light-pink{border-color:#ffa3d7}.swagger-ui .b--dark-green{border-color:#137752}.swagger-ui .b--green{border-color:#19a974}.swagger-ui .b--light-green{border-color:#9eebcf}.swagger-ui .b--navy{border-color:#001b44}.swagger-ui .b--dark-blue{border-color:#00449e}.swagger-ui .b--blue{border-color:#357edd}.swagger-ui .b--light-blue{border-color:#96ccff}.swagger-ui .b--lightest-blue{border-color:#cdecff}.swagger-ui .b--washed-blue{border-color:#f6fffe}.swagger-ui .b--washed-green{border-color:#e8fdf5}.swagger-ui .b--washed-yellow{border-color:#fffceb}.swagger-ui .b--washed-red{border-color:#ffdfdf}.swagger-ui .b--transparent{border-color:transparent}.swagger-ui .b--inherit{border-color:inherit}.swagger-ui .br0{border-radius:0}.swagger-ui .br1{border-radius:.125rem}.swagger-ui .br2{border-radius:.25rem}.swagger-ui .br3{border-radius:.5rem}.swagger-ui .br4{border-radius:1rem}.swagger-ui .br-100{border-radius:100%}.swagger-ui .br-pill{border-radius:9999px}.swagger-ui .br--bottom{border-top-left-radius:0;border-top-right-radius:0}.swagger-ui .br--top{border-bottom-left-radius:0;border-bottom-right-radius:0}.swagger-ui .br--right{border-top-left-radius:0;border-bottom-left-radius:0}.swagger-ui .br--left{border-top-right-radius:0;border-bottom-right-radius:0}@media screen and (min-width:30em){.swagger-ui .br0-ns{border-radius:0}.swagger-ui .br1-ns{border-radius:.125rem}.swagger-ui .br2-ns{border-radius:.25rem}.swagger-ui .br3-ns{border-radius:.5rem}.swagger-ui .br4-ns{border-radius:1rem}.swagger-ui .br-100-ns{border-radius:100%}.swagger-ui .br-pill-ns{border-radius:9999px}.swagger-ui .br--bottom-ns{border-top-left-radius:0;border-top-right-radius:0}.swagger-ui .br--top-ns{border-bottom-left-radius:0;border-bottom-right-radius:0}.swagger-ui .br--right-ns{border-top-left-radius:0;border-bottom-left-radius:0}.swagger-ui .br--left-ns{border-top-right-radius:0;border-bottom-right-radius:0}}@media screen and (min-width:30em) and (max-width:60em){.swagger-ui .br0-m{border-radius:0}.swagger-ui .br1-m{border-radius:.125rem}.swagger-ui .br2-m{border-radius:.25rem}.swagger-ui .br3-m{border-radius:.5rem}.swagger-ui .br4-m{border-radius:1rem}.swagger-ui .br-100-m{border-radius:100%}.swagger-ui .br-pill-m{border-radius:9999px}.swagger-ui .br--bottom-m{border-top-left-radius:0;border-top-right-radius:0}.swagger-ui .br--top-m{border-bottom-left-radius:0;border-bottom-right-radius:0}.swagger-ui .br--right-m{border-top-left-radius:0;border-bottom-left-radius:0}.swagger-ui .br--left-m{border-top-right-radius:0;border-bottom-right-radius:0}}@media screen and (min-width:60em){.swagger-ui .br0-l{border-radius:0}.swagger-ui .br1-l{border-radius:.125rem}.swagger-ui .br2-l{border-radius:.25rem}.swagger-ui .br3-l{border-radius:.5rem}.swagger-ui .br4-l{border-radius:1rem}.swagger-ui .br-100-l{border-radius:100%}.swagger-ui .br-pill-l{border-radius:9999px}.swagger-ui .br--bottom-l{border-top-left-radius:0;border-top-right-radius:0}.swagger-ui .br--top-l{border-bottom-left-radius:0;border-bottom-right-radius:0}.swagger-ui .br--right-l{border-top-left-radius:0;border-bottom-left-radius:0}.swagger-ui .br--left-l{border-top-right-radius:0;border-bottom-right-radius:0}}.swagger-ui .b--dotted{border-style:dotted}.swagger-ui .b--dashed{border-style:dashed}.swagger-ui .b--solid{border-style:solid}.swagger-ui .b--none{border-style:none}@media screen and (min-width:30em){.swagger-ui .b--dotted-ns{border-style:dotted}.swagger-ui .b--dashed-ns{border-style:dashed}.swagger-ui .b--solid-ns{border-style:solid}.swagger-ui .b--none-ns{border-style:none}}@media screen and (min-width:30em) and (max-width:60em){.swagger-ui .b--dotted-m{border-style:dotted}.swagger-ui .b--dashed-m{border-style:dashed}.swagger-ui .b--solid-m{border-style:solid}.swagger-ui .b--none-m{border-style:none}}@media screen and (min-width:60em){.swagger-ui .b--dotted-l{border-style:dotted}.swagger-ui .b--dashed-l{border-style:dashed}.swagger-ui .b--solid-l{border-style:solid}.swagger-ui .b--none-l{border-style:none}}.swagger-ui .bw0{border-width:0}.swagger-ui .bw1{border-width:.125rem}.swagger-ui .bw2{border-width:.25rem}.swagger-ui .bw3{border-width:.5rem}.swagger-ui .bw4{border-width:1rem}.swagger-ui .bw5{border-width:2rem}.swagger-ui .bt-0{border-top-width:0}.swagger-ui .br-0{border-right-width:0}.swagger-ui .bb-0{border-bottom-width:0}.swagger-ui .bl-0{border-left-width:0}@media screen and (min-width:30em){.swagger-ui .bw0-ns{border-width:0}.swagger-ui .bw1-ns{border-width:.125rem}.swagger-ui .bw2-ns{border-width:.25rem}.swagger-ui .bw3-ns{border-width:.5rem}.swagger-ui .bw4-ns{border-width:1rem}.swagger-ui .bw5-ns{border-width:2rem}.swagger-ui .bt-0-ns{border-top-width:0}.swagger-ui .br-0-ns{border-right-width:0}.swagger-ui .bb-0-ns{border-bottom-width:0}.swagger-ui .bl-0-ns{border-left-width:0}}@media screen and (min-width:30em) and (max-width:60em){.swagger-ui .bw0-m{border-width:0}.swagger-ui .bw1-m{border-width:.125rem}.swagger-ui .bw2-m{border-width:.25rem}.swagger-ui .bw3-m{border-width:.5rem}.swagger-ui .bw4-m{border-width:1rem}.swagger-ui .bw5-m{border-width:2rem}.swagger-ui .bt-0-m{border-top-width:0}.swagger-ui .br-0-m{border-right-width:0}.swagger-ui .bb-0-m{border-bottom-width:0}.swagger-ui .bl-0-m{border-left-width:0}}@media screen and (min-width:60em){.swagger-ui .bw0-l{border-width:0}.swagger-ui .bw1-l{border-width:.125rem}.swagger-ui .bw2-l{border-width:.25rem}.swagger-ui .bw3-l{border-width:.5rem}.swagger-ui .bw4-l{border-width:1rem}.swagger-ui .bw5-l{border-width:2rem}.swagger-ui .bt-0-l{border-top-width:0}.swagger-ui .br-0-l{border-right-width:0}.swagger-ui .bb-0-l{border-bottom-width:0}.swagger-ui .bl-0-l{border-left-width:0}}.swagger-ui .shadow-1{box-shadow:0 0 4px 2px rgba(0,0,0,.2)}.swagger-ui .shadow-2{box-shadow:0 0 8px 2px rgba(0,0,0,.2)}.swagger-ui .shadow-3{box-shadow:2px 2px 4px 2px rgba(0,0,0,.2)}.swagger-ui .shadow-4{box-shadow:2px 2px 8px 0 rgba(0,0,0,.2)}.swagger-ui .shadow-5{box-shadow:4px 4px 8px 0 rgba(0,0,0,.2)}@media screen and (min-width:30em){.swagger-ui .shadow-1-ns{box-shadow:0 0 4px 2px rgba(0,0,0,.2)}.swagger-ui .shadow-2-ns{box-shadow:0 0 8px 2px rgba(0,0,0,.2)}.swagger-ui .shadow-3-ns{box-shadow:2px 2px 4px 2px rgba(0,0,0,.2)}.swagger-ui .shadow-4-ns{box-shadow:2px 2px 8px 0 rgba(0,0,0,.2)}.swagger-ui .shadow-5-ns{box-shadow:4px 4px 8px 0 rgba(0,0,0,.2)}}@media screen and (min-width:30em) and (max-width:60em){.swagger-ui .shadow-1-m{box-shadow:0 0 4px 2px rgba(0,0,0,.2)}.swagger-ui .shadow-2-m{box-shadow:0 0 8px 2px rgba(0,0,0,.2)}.swagger-ui .shadow-3-m{box-shadow:2px 2px 4px 2px rgba(0,0,0,.2)}.swagger-ui .shadow-4-m{box-shadow:2px 2px 8px 0 rgba(0,0,0,.2)}.swagger-ui .shadow-5-m{box-shadow:4px 4px 8px 0 rgba(0,0,0,.2)}}@media screen and (min-width:60em){.swagger-ui .shadow-1-l{box-shadow:0 0 4px 2px rgba(0,0,0,.2)}.swagger-ui .shadow-2-l{box-shadow:0 0 8px 2px rgba(0,0,0,.2)}.swagger-ui .shadow-3-l{box-shadow:2px 2px 4px 2px rgba(0,0,0,.2)}.swagger-ui .shadow-4-l{box-shadow:2px 2px 8px 0 rgba(0,0,0,.2)}.swagger-ui .shadow-5-l{box-shadow:4px 4px 8px 0 rgba(0,0,0,.2)}}.swagger-ui .pre{overflow-x:auto;overflow-y:hidden;overflow:scroll}.swagger-ui .top-0{top:0}.swagger-ui .right-0{right:0}.swagger-ui .bottom-0{bottom:0}.swagger-ui .left-0{left:0}.swagger-ui .top-1{top:1rem}.swagger-ui .right-1{right:1rem}.swagger-ui .bottom-1{bottom:1rem}.swagger-ui .left-1{left:1rem}.swagger-ui .top-2{top:2rem}.swagger-ui .right-2{right:2rem}.swagger-ui .bottom-2{bottom:2rem}.swagger-ui .left-2{left:2rem}.swagger-ui .top--1{top:-1rem}.swagger-ui .right--1{right:-1rem}.swagger-ui .bottom--1{bottom:-1rem}.swagger-ui .left--1{left:-1rem}.swagger-ui .top--2{top:-2rem}.swagger-ui .right--2{right:-2rem}.swagger-ui .bottom--2{bottom:-2rem}.swagger-ui .left--2{left:-2rem}.swagger-ui .absolute--fill{top:0;right:0;bottom:0;left:0}@media screen and (min-width:30em){.swagger-ui .top-0-ns{top:0}.swagger-ui .left-0-ns{left:0}.swagger-ui .right-0-ns{right:0}.swagger-ui .bottom-0-ns{bottom:0}.swagger-ui .top-1-ns{top:1rem}.swagger-ui .left-1-ns{left:1rem}.swagger-ui .right-1-ns{right:1rem}.swagger-ui .bottom-1-ns{bottom:1rem}.swagger-ui .top-2-ns{top:2rem}.swagger-ui .left-2-ns{left:2rem}.swagger-ui .right-2-ns{right:2rem}.swagger-ui .bottom-2-ns{bottom:2rem}.swagger-ui .top--1-ns{top:-1rem}.swagger-ui .right--1-ns{right:-1rem}.swagger-ui .bottom--1-ns{bottom:-1rem}.swagger-ui .left--1-ns{left:-1rem}.swagger-ui .top--2-ns{top:-2rem}.swagger-ui .right--2-ns{right:-2rem}.swagger-ui .bottom--2-ns{bottom:-2rem}.swagger-ui .left--2-ns{left:-2rem}.swagger-ui .absolute--fill-ns{top:0;right:0;bottom:0;left:0}}@media screen and (min-width:30em) and (max-width:60em){.swagger-ui .top-0-m{top:0}.swagger-ui .left-0-m{left:0}.swagger-ui .right-0-m{right:0}.swagger-ui .bottom-0-m{bottom:0}.swagger-ui .top-1-m{top:1rem}.swagger-ui .left-1-m{left:1rem}.swagger-ui .right-1-m{right:1rem}.swagger-ui .bottom-1-m{bottom:1rem}.swagger-ui .top-2-m{top:2rem}.swagger-ui .left-2-m{left:2rem}.swagger-ui .right-2-m{right:2rem}.swagger-ui .bottom-2-m{bottom:2rem}.swagger-ui .top--1-m{top:-1rem}.swagger-ui .right--1-m{right:-1rem}.swagger-ui .bottom--1-m{bottom:-1rem}.swagger-ui .left--1-m{left:-1rem}.swagger-ui .top--2-m{top:-2rem}.swagger-ui .right--2-m{right:-2rem}.swagger-ui .bottom--2-m{bottom:-2rem}.swagger-ui .left--2-m{left:-2rem}.swagger-ui .absolute--fill-m{top:0;right:0;bottom:0;left:0}}@media screen and (min-width:60em){.swagger-ui .top-0-l{top:0}.swagger-ui .left-0-l{left:0}.swagger-ui .right-0-l{right:0}.swagger-ui .bottom-0-l{bottom:0}.swagger-ui .top-1-l{top:1rem}.swagger-ui .left-1-l{left:1rem}.swagger-ui .right-1-l{right:1rem}.swagger-ui .bottom-1-l{bottom:1rem}.swagger-ui .top-2-l{top:2rem}.swagger-ui .left-2-l{left:2rem}.swagger-ui .right-2-l{right:2rem}.swagger-ui .bottom-2-l{bottom:2rem}.swagger-ui .top--1-l{top:-1rem}.swagger-ui .right--1-l{right:-1rem}.swagger-ui .bottom--1-l{bottom:-1rem}.swagger-ui .left--1-l{left:-1rem}.swagger-ui .top--2-l{top:-2rem}.swagger-ui .right--2-l{right:-2rem}.swagger-ui .bottom--2-l{bottom:-2rem}.swagger-ui .left--2-l{left:-2rem}.swagger-ui .absolute--fill-l{top:0;right:0;bottom:0;left:0}}.swagger-ui .cf:after,.swagger-ui .cf:before{content:" ";display:table}.swagger-ui .cf:after{clear:both}.swagger-ui .cf{*zoom:1}.swagger-ui .cl{clear:left}.swagger-ui .cr{clear:right}.swagger-ui .cb{clear:both}.swagger-ui .cn{clear:none}@media screen and (min-width:30em){.swagger-ui .cl-ns{clear:left}.swagger-ui .cr-ns{clear:right}.swagger-ui .cb-ns{clear:both}.swagger-ui .cn-ns{clear:none}}@media screen and (min-width:30em) and (max-width:60em){.swagger-ui .cl-m{clear:left}.swagger-ui .cr-m{clear:right}.swagger-ui .cb-m{clear:both}.swagger-ui .cn-m{clear:none}}@media screen and (min-width:60em){.swagger-ui .cl-l{clear:left}.swagger-ui .cr-l{clear:right}.swagger-ui .cb-l{clear:both}.swagger-ui .cn-l{clear:none}}.swagger-ui .flex{display:flex}.swagger-ui .inline-flex{display:inline-flex}.swagger-ui .flex-auto{flex:1 1 auto;min-width:0;min-height:0}.swagger-ui .flex-none{flex:none}.swagger-ui .flex-column{flex-direction:column}.swagger-ui .flex-row{flex-direction:row}.swagger-ui .flex-wrap{flex-wrap:wrap}.swagger-ui .flex-nowrap{flex-wrap:nowrap}.swagger-ui .flex-wrap-reverse{flex-wrap:wrap-reverse}.swagger-ui .flex-column-reverse{flex-direction:column-reverse}.swagger-ui .flex-row-reverse{flex-direction:row-reverse}.swagger-ui .items-start{align-items:flex-start}.swagger-ui .items-end{align-items:flex-end}.swagger-ui .items-center{align-items:center}.swagger-ui .items-baseline{align-items:baseline}.swagger-ui .items-stretch{align-items:stretch}.swagger-ui .self-start{align-self:flex-start}.swagger-ui .self-end{align-self:flex-end}.swagger-ui .self-center{align-self:center}.swagger-ui .self-baseline{align-self:baseline}.swagger-ui .self-stretch{align-self:stretch}.swagger-ui .justify-start{justify-content:flex-start}.swagger-ui .justify-end{justify-content:flex-end}.swagger-ui .justify-center{justify-content:center}.swagger-ui .justify-between{justify-content:space-between}.swagger-ui .justify-around{justify-content:space-around}.swagger-ui .content-start{align-content:flex-start}.swagger-ui .content-end{align-content:flex-end}.swagger-ui .content-center{align-content:center}.swagger-ui .content-between{align-content:space-between}.swagger-ui .content-around{align-content:space-around}.swagger-ui .content-stretch{align-content:stretch}.swagger-ui .order-0{order:0}.swagger-ui .order-1{order:1}.swagger-ui .order-2{order:2}.swagger-ui .order-3{order:3}.swagger-ui .order-4{order:4}.swagger-ui .order-5{order:5}.swagger-ui .order-6{order:6}.swagger-ui .order-7{order:7}.swagger-ui .order-8{order:8}.swagger-ui .order-last{order:99999}.swagger-ui .flex-grow-0{flex-grow:0}.swagger-ui .flex-grow-1{flex-grow:1}.swagger-ui .flex-shrink-0{flex-shrink:0}.swagger-ui .flex-shrink-1{flex-shrink:1}@media screen and (min-width:30em){.swagger-ui .flex-ns{display:flex}.swagger-ui .inline-flex-ns{display:inline-flex}.swagger-ui .flex-auto-ns{flex:1 1 auto;min-width:0;min-height:0}.swagger-ui .flex-none-ns{flex:none}.swagger-ui .flex-column-ns{flex-direction:column}.swagger-ui .flex-row-ns{flex-direction:row}.swagger-ui .flex-wrap-ns{flex-wrap:wrap}.swagger-ui .flex-nowrap-ns{flex-wrap:nowrap}.swagger-ui .flex-wrap-reverse-ns{flex-wrap:wrap-reverse}.swagger-ui .flex-column-reverse-ns{flex-direction:column-reverse}.swagger-ui .flex-row-reverse-ns{flex-direction:row-reverse}.swagger-ui .items-start-ns{align-items:flex-start}.swagger-ui .items-end-ns{align-items:flex-end}.swagger-ui .items-center-ns{align-items:center}.swagger-ui .items-baseline-ns{align-items:baseline}.swagger-ui .items-stretch-ns{align-items:stretch}.swagger-ui .self-start-ns{align-self:flex-start}.swagger-ui .self-end-ns{align-self:flex-end}.swagger-ui .self-center-ns{align-self:center}.swagger-ui .self-baseline-ns{align-self:baseline}.swagger-ui .self-stretch-ns{align-self:stretch}.swagger-ui .justify-start-ns{justify-content:flex-start}.swagger-ui .justify-end-ns{justify-content:flex-end}.swagger-ui .justify-center-ns{justify-content:center}.swagger-ui .justify-between-ns{justify-content:space-between}.swagger-ui .justify-around-ns{justify-content:space-around}.swagger-ui .content-start-ns{align-content:flex-start}.swagger-ui .content-end-ns{align-content:flex-end}.swagger-ui .content-center-ns{align-content:center}.swagger-ui .content-between-ns{align-content:space-between}.swagger-ui .content-around-ns{align-content:space-around}.swagger-ui .content-stretch-ns{align-content:stretch}.swagger-ui .order-0-ns{order:0}.swagger-ui .order-1-ns{order:1}.swagger-ui .order-2-ns{order:2}.swagger-ui .order-3-ns{order:3}.swagger-ui .order-4-ns{order:4}.swagger-ui .order-5-ns{order:5}.swagger-ui .order-6-ns{order:6}.swagger-ui .order-7-ns{order:7}.swagger-ui .order-8-ns{order:8}.swagger-ui .order-last-ns{order:99999}.swagger-ui .flex-grow-0-ns{flex-grow:0}.swagger-ui .flex-grow-1-ns{flex-grow:1}.swagger-ui .flex-shrink-0-ns{flex-shrink:0}.swagger-ui .flex-shrink-1-ns{flex-shrink:1}}@media screen and (min-width:30em) and (max-width:60em){.swagger-ui .flex-m{display:flex}.swagger-ui .inline-flex-m{display:inline-flex}.swagger-ui .flex-auto-m{flex:1 1 auto;min-width:0;min-height:0}.swagger-ui .flex-none-m{flex:none}.swagger-ui .flex-column-m{flex-direction:column}.swagger-ui .flex-row-m{flex-direction:row}.swagger-ui .flex-wrap-m{flex-wrap:wrap}.swagger-ui .flex-nowrap-m{flex-wrap:nowrap}.swagger-ui .flex-wrap-reverse-m{flex-wrap:wrap-reverse}.swagger-ui .flex-column-reverse-m{flex-direction:column-reverse}.swagger-ui .flex-row-reverse-m{flex-direction:row-reverse}.swagger-ui .items-start-m{align-items:flex-start}.swagger-ui .items-end-m{align-items:flex-end}.swagger-ui .items-center-m{align-items:center}.swagger-ui .items-baseline-m{align-items:baseline}.swagger-ui .items-stretch-m{align-items:stretch}.swagger-ui .self-start-m{align-self:flex-start}.swagger-ui .self-end-m{align-self:flex-end}.swagger-ui .self-center-m{align-self:center}.swagger-ui .self-baseline-m{align-self:baseline}.swagger-ui .self-stretch-m{align-self:stretch}.swagger-ui .justify-start-m{justify-content:flex-start}.swagger-ui .justify-end-m{justify-content:flex-end}.swagger-ui .justify-center-m{justify-content:center}.swagger-ui .justify-between-m{justify-content:space-between}.swagger-ui .justify-around-m{justify-content:space-around}.swagger-ui .content-start-m{align-content:flex-start}.swagger-ui .content-end-m{align-content:flex-end}.swagger-ui .content-center-m{align-content:center}.swagger-ui .content-between-m{align-content:space-between}.swagger-ui .content-around-m{align-content:space-around}.swagger-ui .content-stretch-m{align-content:stretch}.swagger-ui .order-0-m{order:0}.swagger-ui .order-1-m{order:1}.swagger-ui .order-2-m{order:2}.swagger-ui .order-3-m{order:3}.swagger-ui .order-4-m{order:4}.swagger-ui .order-5-m{order:5}.swagger-ui .order-6-m{order:6}.swagger-ui .order-7-m{order:7}.swagger-ui .order-8-m{order:8}.swagger-ui .order-last-m{order:99999}.swagger-ui .flex-grow-0-m{flex-grow:0}.swagger-ui .flex-grow-1-m{flex-grow:1}.swagger-ui .flex-shrink-0-m{flex-shrink:0}.swagger-ui .flex-shrink-1-m{flex-shrink:1}}@media screen and (min-width:60em){.swagger-ui .flex-l{display:flex}.swagger-ui .inline-flex-l{display:inline-flex}.swagger-ui .flex-auto-l{flex:1 1 auto;min-width:0;min-height:0}.swagger-ui .flex-none-l{flex:none}.swagger-ui .flex-column-l{flex-direction:column}.swagger-ui .flex-row-l{flex-direction:row}.swagger-ui .flex-wrap-l{flex-wrap:wrap}.swagger-ui .flex-nowrap-l{flex-wrap:nowrap}.swagger-ui .flex-wrap-reverse-l{flex-wrap:wrap-reverse}.swagger-ui .flex-column-reverse-l{flex-direction:column-reverse}.swagger-ui .flex-row-reverse-l{flex-direction:row-reverse}.swagger-ui .items-start-l{align-items:flex-start}.swagger-ui .items-end-l{align-items:flex-end}.swagger-ui .items-center-l{align-items:center}.swagger-ui .items-baseline-l{align-items:baseline}.swagger-ui .items-stretch-l{align-items:stretch}.swagger-ui .self-start-l{align-self:flex-start}.swagger-ui .self-end-l{align-self:flex-end}.swagger-ui .self-center-l{align-self:center}.swagger-ui .self-baseline-l{align-self:baseline}.swagger-ui .self-stretch-l{align-self:stretch}.swagger-ui .justify-start-l{justify-content:flex-start}.swagger-ui .justify-end-l{justify-content:flex-end}.swagger-ui .justify-center-l{justify-content:center}.swagger-ui .justify-between-l{justify-content:space-between}.swagger-ui .justify-around-l{justify-content:space-around}.swagger-ui .content-start-l{align-content:flex-start}.swagger-ui .content-end-l{align-content:flex-end}.swagger-ui .content-center-l{align-content:center}.swagger-ui .content-between-l{align-content:space-between}.swagger-ui .content-around-l{align-content:space-around}.swagger-ui .content-stretch-l{align-content:stretch}.swagger-ui .order-0-l{order:0}.swagger-ui .order-1-l{order:1}.swagger-ui .order-2-l{order:2}.swagger-ui .order-3-l{order:3}.swagger-ui .order-4-l{order:4}.swagger-ui .order-5-l{order:5}.swagger-ui .order-6-l{order:6}.swagger-ui .order-7-l{order:7}.swagger-ui .order-8-l{order:8}.swagger-ui .order-last-l{order:99999}.swagger-ui .flex-grow-0-l{flex-grow:0}.swagger-ui .flex-grow-1-l{flex-grow:1}.swagger-ui .flex-shrink-0-l{flex-shrink:0}.swagger-ui .flex-shrink-1-l{flex-shrink:1}}.swagger-ui .dn{display:none}.swagger-ui .di{display:inline}.swagger-ui .db{display:block}.swagger-ui .dib{display:inline-block}.swagger-ui .dit{display:inline-table}.swagger-ui .dt{display:table}.swagger-ui .dtc{display:table-cell}.swagger-ui .dt-row{display:table-row}.swagger-ui .dt-row-group{display:table-row-group}.swagger-ui .dt-column{display:table-column}.swagger-ui .dt-column-group{display:table-column-group}.swagger-ui .dt--fixed{table-layout:fixed;width:100%}@media screen and (min-width:30em){.swagger-ui .dn-ns{display:none}.swagger-ui .di-ns{display:inline}.swagger-ui .db-ns{display:block}.swagger-ui .dib-ns{display:inline-block}.swagger-ui .dit-ns{display:inline-table}.swagger-ui .dt-ns{display:table}.swagger-ui .dtc-ns{display:table-cell}.swagger-ui .dt-row-ns{display:table-row}.swagger-ui .dt-row-group-ns{display:table-row-group}.swagger-ui .dt-column-ns{display:table-column}.swagger-ui .dt-column-group-ns{display:table-column-group}.swagger-ui .dt--fixed-ns{table-layout:fixed;width:100%}}@media screen and (min-width:30em) and (max-width:60em){.swagger-ui .dn-m{display:none}.swagger-ui .di-m{display:inline}.swagger-ui .db-m{display:block}.swagger-ui .dib-m{display:inline-block}.swagger-ui .dit-m{display:inline-table}.swagger-ui .dt-m{display:table}.swagger-ui .dtc-m{display:table-cell}.swagger-ui .dt-row-m{display:table-row}.swagger-ui .dt-row-group-m{display:table-row-group}.swagger-ui .dt-column-m{display:table-column}.swagger-ui .dt-column-group-m{display:table-column-group}.swagger-ui .dt--fixed-m{table-layout:fixed;width:100%}}@media screen and (min-width:60em){.swagger-ui .dn-l{display:none}.swagger-ui .di-l{display:inline}.swagger-ui .db-l{display:block}.swagger-ui .dib-l{display:inline-block}.swagger-ui .dit-l{display:inline-table}.swagger-ui .dt-l{display:table}.swagger-ui .dtc-l{display:table-cell}.swagger-ui .dt-row-l{display:table-row}.swagger-ui .dt-row-group-l{display:table-row-group}.swagger-ui .dt-column-l{display:table-column}.swagger-ui .dt-column-group-l{display:table-column-group}.swagger-ui .dt--fixed-l{table-layout:fixed;width:100%}}.swagger-ui .fl{float:left;_display:inline}.swagger-ui .fr{float:right;_display:inline}.swagger-ui .fn{float:none}@media screen and (min-width:30em){.swagger-ui .fl-ns{float:left;_display:inline}.swagger-ui .fr-ns{float:right;_display:inline}.swagger-ui .fn-ns{float:none}}@media screen and (min-width:30em) and (max-width:60em){.swagger-ui .fl-m{float:left;_display:inline}.swagger-ui .fr-m{float:right;_display:inline}.swagger-ui .fn-m{float:none}}@media screen and (min-width:60em){.swagger-ui .fl-l{float:left;_display:inline}.swagger-ui .fr-l{float:right;_display:inline}.swagger-ui .fn-l{float:none}}.swagger-ui .sans-serif{font-family:-apple-system,BlinkMacSystemFont,avenir next,avenir,helvetica,helvetica neue,ubuntu,roboto,noto,segoe ui,arial,sans-serif}.swagger-ui .serif{font-family:georgia,serif}.swagger-ui .system-sans-serif{font-family:sans-serif}.swagger-ui .system-serif{font-family:serif}.swagger-ui .code,.swagger-ui code{font-family:Consolas,monaco,monospace}.swagger-ui .courier{font-family:Courier Next,courier,monospace}.swagger-ui .helvetica{font-family:helvetica neue,helvetica,sans-serif}.swagger-ui .avenir{font-family:avenir next,avenir,sans-serif}.swagger-ui .athelas{font-family:athelas,georgia,serif}.swagger-ui .georgia{font-family:georgia,serif}.swagger-ui .times{font-family:times,serif}.swagger-ui .bodoni{font-family:Bodoni MT,serif}.swagger-ui .calisto{font-family:Calisto MT,serif}.swagger-ui .garamond{font-family:garamond,serif}.swagger-ui .baskerville{font-family:baskerville,serif}.swagger-ui .i{font-style:italic}.swagger-ui .fs-normal{font-style:normal}@media screen and (min-width:30em){.swagger-ui .i-ns{font-style:italic}.swagger-ui .fs-normal-ns{font-style:normal}}@media screen and (min-width:30em) and (max-width:60em){.swagger-ui .i-m{font-style:italic}.swagger-ui .fs-normal-m{font-style:normal}}@media screen and (min-width:60em){.swagger-ui .i-l{font-style:italic}.swagger-ui .fs-normal-l{font-style:normal}}.swagger-ui .normal{font-weight:400}.swagger-ui .b{font-weight:700}.swagger-ui .fw1{font-weight:100}.swagger-ui .fw2{font-weight:200}.swagger-ui .fw3{font-weight:300}.swagger-ui .fw4{font-weight:400}.swagger-ui .fw5{font-weight:500}.swagger-ui .fw6{font-weight:600}.swagger-ui .fw7{font-weight:700}.swagger-ui .fw8{font-weight:800}.swagger-ui .fw9{font-weight:900}@media screen and (min-width:30em){.swagger-ui .normal-ns{font-weight:400}.swagger-ui .b-ns{font-weight:700}.swagger-ui .fw1-ns{font-weight:100}.swagger-ui .fw2-ns{font-weight:200}.swagger-ui .fw3-ns{font-weight:300}.swagger-ui .fw4-ns{font-weight:400}.swagger-ui .fw5-ns{font-weight:500}.swagger-ui .fw6-ns{font-weight:600}.swagger-ui .fw7-ns{font-weight:700}.swagger-ui .fw8-ns{font-weight:800}.swagger-ui .fw9-ns{font-weight:900}}@media screen and (min-width:30em) and (max-width:60em){.swagger-ui .normal-m{font-weight:400}.swagger-ui .b-m{font-weight:700}.swagger-ui .fw1-m{font-weight:100}.swagger-ui .fw2-m{font-weight:200}.swagger-ui .fw3-m{font-weight:300}.swagger-ui .fw4-m{font-weight:400}.swagger-ui .fw5-m{font-weight:500}.swagger-ui .fw6-m{font-weight:600}.swagger-ui .fw7-m{font-weight:700}.swagger-ui .fw8-m{font-weight:800}.swagger-ui .fw9-m{font-weight:900}}@media screen and (min-width:60em){.swagger-ui .normal-l{font-weight:400}.swagger-ui .b-l{font-weight:700}.swagger-ui .fw1-l{font-weight:100}.swagger-ui .fw2-l{font-weight:200}.swagger-ui .fw3-l{font-weight:300}.swagger-ui .fw4-l{font-weight:400}.swagger-ui .fw5-l{font-weight:500}.swagger-ui .fw6-l{font-weight:600}.swagger-ui .fw7-l{font-weight:700}.swagger-ui .fw8-l{font-weight:800}.swagger-ui .fw9-l{font-weight:900}}.swagger-ui .input-reset{-webkit-appearance:none;-moz-appearance:none}.swagger-ui .button-reset::-moz-focus-inner,.swagger-ui .input-reset::-moz-focus-inner{border:0;padding:0}.swagger-ui .h1{height:1rem}.swagger-ui .h2{height:2rem}.swagger-ui .h3{height:4rem}.swagger-ui .h4{height:8rem}.swagger-ui .h5{height:16rem}.swagger-ui .h-25{height:25%}.swagger-ui .h-50{height:50%}.swagger-ui .h-75{height:75%}.swagger-ui .h-100{height:100%}.swagger-ui .min-h-100{min-height:100%}.swagger-ui .vh-25{height:25vh}.swagger-ui .vh-50{height:50vh}.swagger-ui .vh-75{height:75vh}.swagger-ui .vh-100{height:100vh}.swagger-ui .min-vh-100{min-height:100vh}.swagger-ui .h-auto{height:auto}.swagger-ui .h-inherit{height:inherit}@media screen and (min-width:30em){.swagger-ui .h1-ns{height:1rem}.swagger-ui .h2-ns{height:2rem}.swagger-ui .h3-ns{height:4rem}.swagger-ui .h4-ns{height:8rem}.swagger-ui .h5-ns{height:16rem}.swagger-ui .h-25-ns{height:25%}.swagger-ui .h-50-ns{height:50%}.swagger-ui .h-75-ns{height:75%}.swagger-ui .h-100-ns{height:100%}.swagger-ui .min-h-100-ns{min-height:100%}.swagger-ui .vh-25-ns{height:25vh}.swagger-ui .vh-50-ns{height:50vh}.swagger-ui .vh-75-ns{height:75vh}.swagger-ui .vh-100-ns{height:100vh}.swagger-ui .min-vh-100-ns{min-height:100vh}.swagger-ui .h-auto-ns{height:auto}.swagger-ui .h-inherit-ns{height:inherit}}@media screen and (min-width:30em) and (max-width:60em){.swagger-ui .h1-m{height:1rem}.swagger-ui .h2-m{height:2rem}.swagger-ui .h3-m{height:4rem}.swagger-ui .h4-m{height:8rem}.swagger-ui .h5-m{height:16rem}.swagger-ui .h-25-m{height:25%}.swagger-ui .h-50-m{height:50%}.swagger-ui .h-75-m{height:75%}.swagger-ui .h-100-m{height:100%}.swagger-ui .min-h-100-m{min-height:100%}.swagger-ui .vh-25-m{height:25vh}.swagger-ui .vh-50-m{height:50vh}.swagger-ui .vh-75-m{height:75vh}.swagger-ui .vh-100-m{height:100vh}.swagger-ui .min-vh-100-m{min-height:100vh}.swagger-ui .h-auto-m{height:auto}.swagger-ui .h-inherit-m{height:inherit}}@media screen and (min-width:60em){.swagger-ui .h1-l{height:1rem}.swagger-ui .h2-l{height:2rem}.swagger-ui .h3-l{height:4rem}.swagger-ui .h4-l{height:8rem}.swagger-ui .h5-l{height:16rem}.swagger-ui .h-25-l{height:25%}.swagger-ui .h-50-l{height:50%}.swagger-ui .h-75-l{height:75%}.swagger-ui .h-100-l{height:100%}.swagger-ui .min-h-100-l{min-height:100%}.swagger-ui .vh-25-l{height:25vh}.swagger-ui .vh-50-l{height:50vh}.swagger-ui .vh-75-l{height:75vh}.swagger-ui .vh-100-l{height:100vh}.swagger-ui .min-vh-100-l{min-height:100vh}.swagger-ui .h-auto-l{height:auto}.swagger-ui .h-inherit-l{height:inherit}}.swagger-ui .tracked{letter-spacing:.1em}.swagger-ui .tracked-tight{letter-spacing:-.05em}.swagger-ui .tracked-mega{letter-spacing:.25em}@media screen and (min-width:30em){.swagger-ui .tracked-ns{letter-spacing:.1em}.swagger-ui .tracked-tight-ns{letter-spacing:-.05em}.swagger-ui .tracked-mega-ns{letter-spacing:.25em}}@media screen and (min-width:30em) and (max-width:60em){.swagger-ui .tracked-m{letter-spacing:.1em}.swagger-ui .tracked-tight-m{letter-spacing:-.05em}.swagger-ui .tracked-mega-m{letter-spacing:.25em}}@media screen and (min-width:60em){.swagger-ui .tracked-l{letter-spacing:.1em}.swagger-ui .tracked-tight-l{letter-spacing:-.05em}.swagger-ui .tracked-mega-l{letter-spacing:.25em}}.swagger-ui .lh-solid{line-height:1}.swagger-ui .lh-title{line-height:1.25}.swagger-ui .lh-copy{line-height:1.5}@media screen and (min-width:30em){.swagger-ui .lh-solid-ns{line-height:1}.swagger-ui .lh-title-ns{line-height:1.25}.swagger-ui .lh-copy-ns{line-height:1.5}}@media screen and (min-width:30em) and (max-width:60em){.swagger-ui .lh-solid-m{line-height:1}.swagger-ui .lh-title-m{line-height:1.25}.swagger-ui .lh-copy-m{line-height:1.5}}@media screen and (min-width:60em){.swagger-ui .lh-solid-l{line-height:1}.swagger-ui .lh-title-l{line-height:1.25}.swagger-ui .lh-copy-l{line-height:1.5}}.swagger-ui .link{text-decoration:none}.swagger-ui .link,.swagger-ui .link:link,.swagger-ui .link:visited{transition:color .15s ease-in}.swagger-ui .link:hover{transition:color .15s ease-in}.swagger-ui .link:active{transition:color .15s ease-in}.swagger-ui .link:focus{transition:color .15s ease-in;outline:1px dotted currentColor}.swagger-ui .list{list-style-type:none}.swagger-ui .mw-100{max-width:100%}.swagger-ui .mw1{max-width:1rem}.swagger-ui .mw2{max-width:2rem}.swagger-ui .mw3{max-width:4rem}.swagger-ui .mw4{max-width:8rem}.swagger-ui .mw5{max-width:16rem}.swagger-ui .mw6{max-width:32rem}.swagger-ui .mw7{max-width:48rem}.swagger-ui .mw8{max-width:64rem}.swagger-ui .mw9{max-width:96rem}.swagger-ui .mw-none{max-width:none}@media screen and (min-width:30em){.swagger-ui .mw-100-ns{max-width:100%}.swagger-ui .mw1-ns{max-width:1rem}.swagger-ui .mw2-ns{max-width:2rem}.swagger-ui .mw3-ns{max-width:4rem}.swagger-ui .mw4-ns{max-width:8rem}.swagger-ui .mw5-ns{max-width:16rem}.swagger-ui .mw6-ns{max-width:32rem}.swagger-ui .mw7-ns{max-width:48rem}.swagger-ui .mw8-ns{max-width:64rem}.swagger-ui .mw9-ns{max-width:96rem}.swagger-ui .mw-none-ns{max-width:none}}@media screen and (min-width:30em) and (max-width:60em){.swagger-ui .mw-100-m{max-width:100%}.swagger-ui .mw1-m{max-width:1rem}.swagger-ui .mw2-m{max-width:2rem}.swagger-ui .mw3-m{max-width:4rem}.swagger-ui .mw4-m{max-width:8rem}.swagger-ui .mw5-m{max-width:16rem}.swagger-ui .mw6-m{max-width:32rem}.swagger-ui .mw7-m{max-width:48rem}.swagger-ui .mw8-m{max-width:64rem}.swagger-ui .mw9-m{max-width:96rem}.swagger-ui .mw-none-m{max-width:none}}@media screen and (min-width:60em){.swagger-ui .mw-100-l{max-width:100%}.swagger-ui .mw1-l{max-width:1rem}.swagger-ui .mw2-l{max-width:2rem}.swagger-ui .mw3-l{max-width:4rem}.swagger-ui .mw4-l{max-width:8rem}.swagger-ui .mw5-l{max-width:16rem}.swagger-ui .mw6-l{max-width:32rem}.swagger-ui .mw7-l{max-width:48rem}.swagger-ui .mw8-l{max-width:64rem}.swagger-ui .mw9-l{max-width:96rem}.swagger-ui .mw-none-l{max-width:none}}.swagger-ui .w1{width:1rem}.swagger-ui .w2{width:2rem}.swagger-ui .w3{width:4rem}.swagger-ui .w4{width:8rem}.swagger-ui .w5{width:16rem}.swagger-ui .w-10{width:10%}.swagger-ui .w-20{width:20%}.swagger-ui .w-25{width:25%}.swagger-ui .w-30{width:30%}.swagger-ui .w-33{width:33%}.swagger-ui .w-34{width:34%}.swagger-ui .w-40{width:40%}.swagger-ui .w-50{width:50%}.swagger-ui .w-60{width:60%}.swagger-ui .w-70{width:70%}.swagger-ui .w-75{width:75%}.swagger-ui .w-80{width:80%}.swagger-ui .w-90{width:90%}.swagger-ui .w-100{width:100%}.swagger-ui .w-third{width:33.33333%}.swagger-ui .w-two-thirds{width:66.66667%}.swagger-ui .w-auto{width:auto}@media screen and (min-width:30em){.swagger-ui .w1-ns{width:1rem}.swagger-ui .w2-ns{width:2rem}.swagger-ui .w3-ns{width:4rem}.swagger-ui .w4-ns{width:8rem}.swagger-ui .w5-ns{width:16rem}.swagger-ui .w-10-ns{width:10%}.swagger-ui .w-20-ns{width:20%}.swagger-ui .w-25-ns{width:25%}.swagger-ui .w-30-ns{width:30%}.swagger-ui .w-33-ns{width:33%}.swagger-ui .w-34-ns{width:34%}.swagger-ui .w-40-ns{width:40%}.swagger-ui .w-50-ns{width:50%}.swagger-ui .w-60-ns{width:60%}.swagger-ui .w-70-ns{width:70%}.swagger-ui .w-75-ns{width:75%}.swagger-ui .w-80-ns{width:80%}.swagger-ui .w-90-ns{width:90%}.swagger-ui .w-100-ns{width:100%}.swagger-ui .w-third-ns{width:33.33333%}.swagger-ui .w-two-thirds-ns{width:66.66667%}.swagger-ui .w-auto-ns{width:auto}}@media screen and (min-width:30em) and (max-width:60em){.swagger-ui .w1-m{width:1rem}.swagger-ui .w2-m{width:2rem}.swagger-ui .w3-m{width:4rem}.swagger-ui .w4-m{width:8rem}.swagger-ui .w5-m{width:16rem}.swagger-ui .w-10-m{width:10%}.swagger-ui .w-20-m{width:20%}.swagger-ui .w-25-m{width:25%}.swagger-ui .w-30-m{width:30%}.swagger-ui .w-33-m{width:33%}.swagger-ui .w-34-m{width:34%}.swagger-ui .w-40-m{width:40%}.swagger-ui .w-50-m{width:50%}.swagger-ui .w-60-m{width:60%}.swagger-ui .w-70-m{width:70%}.swagger-ui .w-75-m{width:75%}.swagger-ui .w-80-m{width:80%}.swagger-ui .w-90-m{width:90%}.swagger-ui .w-100-m{width:100%}.swagger-ui .w-third-m{width:33.33333%}.swagger-ui .w-two-thirds-m{width:66.66667%}.swagger-ui .w-auto-m{width:auto}}@media screen and (min-width:60em){.swagger-ui .w1-l{width:1rem}.swagger-ui .w2-l{width:2rem}.swagger-ui .w3-l{width:4rem}.swagger-ui .w4-l{width:8rem}.swagger-ui .w5-l{width:16rem}.swagger-ui .w-10-l{width:10%}.swagger-ui .w-20-l{width:20%}.swagger-ui .w-25-l{width:25%}.swagger-ui .w-30-l{width:30%}.swagger-ui .w-33-l{width:33%}.swagger-ui .w-34-l{width:34%}.swagger-ui .w-40-l{width:40%}.swagger-ui .w-50-l{width:50%}.swagger-ui .w-60-l{width:60%}.swagger-ui .w-70-l{width:70%}.swagger-ui .w-75-l{width:75%}.swagger-ui .w-80-l{width:80%}.swagger-ui .w-90-l{width:90%}.swagger-ui .w-100-l{width:100%}.swagger-ui .w-third-l{width:33.33333%}.swagger-ui .w-two-thirds-l{width:66.66667%}.swagger-ui .w-auto-l{width:auto}}.swagger-ui .overflow-visible{overflow:visible}.swagger-ui .overflow-hidden{overflow:hidden}.swagger-ui .overflow-scroll{overflow:scroll}.swagger-ui .overflow-auto{overflow:auto}.swagger-ui .overflow-x-visible{overflow-x:visible}.swagger-ui .overflow-x-hidden{overflow-x:hidden}.swagger-ui .overflow-x-scroll{overflow-x:scroll}.swagger-ui .overflow-x-auto{overflow-x:auto}.swagger-ui .overflow-y-visible{overflow-y:visible}.swagger-ui .overflow-y-hidden{overflow-y:hidden}.swagger-ui .overflow-y-scroll{overflow-y:scroll}.swagger-ui .overflow-y-auto{overflow-y:auto}@media screen and (min-width:30em){.swagger-ui .overflow-visible-ns{overflow:visible}.swagger-ui .overflow-hidden-ns{overflow:hidden}.swagger-ui .overflow-scroll-ns{overflow:scroll}.swagger-ui .overflow-auto-ns{overflow:auto}.swagger-ui .overflow-x-visible-ns{overflow-x:visible}.swagger-ui .overflow-x-hidden-ns{overflow-x:hidden}.swagger-ui .overflow-x-scroll-ns{overflow-x:scroll}.swagger-ui .overflow-x-auto-ns{overflow-x:auto}.swagger-ui .overflow-y-visible-ns{overflow-y:visible}.swagger-ui .overflow-y-hidden-ns{overflow-y:hidden}.swagger-ui .overflow-y-scroll-ns{overflow-y:scroll}.swagger-ui .overflow-y-auto-ns{overflow-y:auto}}@media screen and (min-width:30em) and (max-width:60em){.swagger-ui .overflow-visible-m{overflow:visible}.swagger-ui .overflow-hidden-m{overflow:hidden}.swagger-ui .overflow-scroll-m{overflow:scroll}.swagger-ui .overflow-auto-m{overflow:auto}.swagger-ui .overflow-x-visible-m{overflow-x:visible}.swagger-ui .overflow-x-hidden-m{overflow-x:hidden}.swagger-ui .overflow-x-scroll-m{overflow-x:scroll}.swagger-ui .overflow-x-auto-m{overflow-x:auto}.swagger-ui .overflow-y-visible-m{overflow-y:visible}.swagger-ui .overflow-y-hidden-m{overflow-y:hidden}.swagger-ui .overflow-y-scroll-m{overflow-y:scroll}.swagger-ui .overflow-y-auto-m{overflow-y:auto}}@media screen and (min-width:60em){.swagger-ui .overflow-visible-l{overflow:visible}.swagger-ui .overflow-hidden-l{overflow:hidden}.swagger-ui .overflow-scroll-l{overflow:scroll}.swagger-ui .overflow-auto-l{overflow:auto}.swagger-ui .overflow-x-visible-l{overflow-x:visible}.swagger-ui .overflow-x-hidden-l{overflow-x:hidden}.swagger-ui .overflow-x-scroll-l{overflow-x:scroll}.swagger-ui .overflow-x-auto-l{overflow-x:auto}.swagger-ui .overflow-y-visible-l{overflow-y:visible}.swagger-ui .overflow-y-hidden-l{overflow-y:hidden}.swagger-ui .overflow-y-scroll-l{overflow-y:scroll}.swagger-ui .overflow-y-auto-l{overflow-y:auto}}.swagger-ui .static{position:static}.swagger-ui .relative{position:relative}.swagger-ui .absolute{position:absolute}.swagger-ui .fixed{position:fixed}@media screen and (min-width:30em){.swagger-ui .static-ns{position:static}.swagger-ui .relative-ns{position:relative}.swagger-ui .absolute-ns{position:absolute}.swagger-ui .fixed-ns{position:fixed}}@media screen and (min-width:30em) and (max-width:60em){.swagger-ui .static-m{position:static}.swagger-ui .relative-m{position:relative}.swagger-ui .absolute-m{position:absolute}.swagger-ui .fixed-m{position:fixed}}@media screen and (min-width:60em){.swagger-ui .static-l{position:static}.swagger-ui .relative-l{position:relative}.swagger-ui .absolute-l{position:absolute}.swagger-ui .fixed-l{position:fixed}}.swagger-ui .o-100{opacity:1}.swagger-ui .o-90{opacity:.9}.swagger-ui .o-80{opacity:.8}.swagger-ui .o-70{opacity:.7}.swagger-ui .o-60{opacity:.6}.swagger-ui .o-50{opacity:.5}.swagger-ui .o-40{opacity:.4}.swagger-ui .o-30{opacity:.3}.swagger-ui .o-20{opacity:.2}.swagger-ui .o-10{opacity:.1}.swagger-ui .o-05{opacity:.05}.swagger-ui .o-025{opacity:.025}.swagger-ui .o-0{opacity:0}.swagger-ui .rotate-45{-webkit-transform:rotate(45deg);transform:rotate(45deg)}.swagger-ui .rotate-90{-webkit-transform:rotate(90deg);transform:rotate(90deg)}.swagger-ui .rotate-135{-webkit-transform:rotate(135deg);transform:rotate(135deg)}.swagger-ui .rotate-180{-webkit-transform:rotate(180deg);transform:rotate(180deg)}.swagger-ui .rotate-225{-webkit-transform:rotate(225deg);transform:rotate(225deg)}.swagger-ui .rotate-270{-webkit-transform:rotate(270deg);transform:rotate(270deg)}.swagger-ui .rotate-315{-webkit-transform:rotate(315deg);transform:rotate(315deg)}@media screen and (min-width:30em){.swagger-ui .rotate-45-ns{-webkit-transform:rotate(45deg);transform:rotate(45deg)}.swagger-ui .rotate-90-ns{-webkit-transform:rotate(90deg);transform:rotate(90deg)}.swagger-ui .rotate-135-ns{-webkit-transform:rotate(135deg);transform:rotate(135deg)}.swagger-ui .rotate-180-ns{-webkit-transform:rotate(180deg);transform:rotate(180deg)}.swagger-ui .rotate-225-ns{-webkit-transform:rotate(225deg);transform:rotate(225deg)}.swagger-ui .rotate-270-ns{-webkit-transform:rotate(270deg);transform:rotate(270deg)}.swagger-ui .rotate-315-ns{-webkit-transform:rotate(315deg);transform:rotate(315deg)}}@media screen and (min-width:30em) and (max-width:60em){.swagger-ui .rotate-45-m{-webkit-transform:rotate(45deg);transform:rotate(45deg)}.swagger-ui .rotate-90-m{-webkit-transform:rotate(90deg);transform:rotate(90deg)}.swagger-ui .rotate-135-m{-webkit-transform:rotate(135deg);transform:rotate(135deg)}.swagger-ui .rotate-180-m{-webkit-transform:rotate(180deg);transform:rotate(180deg)}.swagger-ui .rotate-225-m{-webkit-transform:rotate(225deg);transform:rotate(225deg)}.swagger-ui .rotate-270-m{-webkit-transform:rotate(270deg);transform:rotate(270deg)}.swagger-ui .rotate-315-m{-webkit-transform:rotate(315deg);transform:rotate(315deg)}}@media screen and (min-width:60em){.swagger-ui .rotate-45-l{-webkit-transform:rotate(45deg);transform:rotate(45deg)}.swagger-ui .rotate-90-l{-webkit-transform:rotate(90deg);transform:rotate(90deg)}.swagger-ui .rotate-135-l{-webkit-transform:rotate(135deg);transform:rotate(135deg)}.swagger-ui .rotate-180-l{-webkit-transform:rotate(180deg);transform:rotate(180deg)}.swagger-ui .rotate-225-l{-webkit-transform:rotate(225deg);transform:rotate(225deg)}.swagger-ui .rotate-270-l{-webkit-transform:rotate(270deg);transform:rotate(270deg)}.swagger-ui .rotate-315-l{-webkit-transform:rotate(315deg);transform:rotate(315deg)}}.swagger-ui .black-90{color:rgba(0,0,0,.9)}.swagger-ui .black-80{color:rgba(0,0,0,.8)}.swagger-ui .black-70{color:rgba(0,0,0,.7)}.swagger-ui .black-60{color:rgba(0,0,0,.6)}.swagger-ui .black-50{color:rgba(0,0,0,.5)}.swagger-ui .black-40{color:rgba(0,0,0,.4)}.swagger-ui .black-30{color:rgba(0,0,0,.3)}.swagger-ui .black-20{color:rgba(0,0,0,.2)}.swagger-ui .black-10{color:rgba(0,0,0,.1)}.swagger-ui .black-05{color:rgba(0,0,0,.05)}.swagger-ui .white-90{color:hsla(0,0%,100%,.9)}.swagger-ui .white-80{color:hsla(0,0%,100%,.8)}.swagger-ui .white-70{color:hsla(0,0%,100%,.7)}.swagger-ui .white-60{color:hsla(0,0%,100%,.6)}.swagger-ui .white-50{color:hsla(0,0%,100%,.5)}.swagger-ui .white-40{color:hsla(0,0%,100%,.4)}.swagger-ui .white-30{color:hsla(0,0%,100%,.3)}.swagger-ui .white-20{color:hsla(0,0%,100%,.2)}.swagger-ui .white-10{color:hsla(0,0%,100%,.1)}.swagger-ui .black{color:#000}.swagger-ui .near-black{color:#111}.swagger-ui .dark-gray{color:#333}.swagger-ui .mid-gray{color:#555}.swagger-ui .gray{color:#777}.swagger-ui .silver{color:#999}.swagger-ui .light-silver{color:#aaa}.swagger-ui .moon-gray{color:#ccc}.swagger-ui .light-gray{color:#eee}.swagger-ui .near-white{color:#f4f4f4}.swagger-ui .white{color:#fff}.swagger-ui .dark-red{color:#e7040f}.swagger-ui .red{color:#ff4136}.swagger-ui .light-red{color:#ff725c}.swagger-ui .orange{color:#ff6300}.swagger-ui .gold{color:#ffb700}.swagger-ui .yellow{color:gold}.swagger-ui .light-yellow{color:#fbf1a9}.swagger-ui .purple{color:#5e2ca5}.swagger-ui .light-purple{color:#a463f2}.swagger-ui .dark-pink{color:#d5008f}.swagger-ui .hot-pink{color:#ff41b4}.swagger-ui .pink{color:#ff80cc}.swagger-ui .light-pink{color:#ffa3d7}.swagger-ui .dark-green{color:#137752}.swagger-ui .green{color:#19a974}.swagger-ui .light-green{color:#9eebcf}.swagger-ui .navy{color:#001b44}.swagger-ui .dark-blue{color:#00449e}.swagger-ui .blue{color:#357edd}.swagger-ui .light-blue{color:#96ccff}.swagger-ui .lightest-blue{color:#cdecff}.swagger-ui .washed-blue{color:#f6fffe}.swagger-ui .washed-green{color:#e8fdf5}.swagger-ui .washed-yellow{color:#fffceb}.swagger-ui .washed-red{color:#ffdfdf}.swagger-ui .color-inherit{color:inherit}.swagger-ui .bg-black-90{background-color:rgba(0,0,0,.9)}.swagger-ui .bg-black-80{background-color:rgba(0,0,0,.8)}.swagger-ui .bg-black-70{background-color:rgba(0,0,0,.7)}.swagger-ui .bg-black-60{background-color:rgba(0,0,0,.6)}.swagger-ui .bg-black-50{background-color:rgba(0,0,0,.5)}.swagger-ui .bg-black-40{background-color:rgba(0,0,0,.4)}.swagger-ui .bg-black-30{background-color:rgba(0,0,0,.3)}.swagger-ui .bg-black-20{background-color:rgba(0,0,0,.2)}.swagger-ui .bg-black-10{background-color:rgba(0,0,0,.1)}.swagger-ui .bg-black-05{background-color:rgba(0,0,0,.05)}.swagger-ui .bg-white-90{background-color:hsla(0,0%,100%,.9)}.swagger-ui .bg-white-80{background-color:hsla(0,0%,100%,.8)}.swagger-ui .bg-white-70{background-color:hsla(0,0%,100%,.7)}.swagger-ui .bg-white-60{background-color:hsla(0,0%,100%,.6)}.swagger-ui .bg-white-50{background-color:hsla(0,0%,100%,.5)}.swagger-ui .bg-white-40{background-color:hsla(0,0%,100%,.4)}.swagger-ui .bg-white-30{background-color:hsla(0,0%,100%,.3)}.swagger-ui .bg-white-20{background-color:hsla(0,0%,100%,.2)}.swagger-ui .bg-white-10{background-color:hsla(0,0%,100%,.1)}.swagger-ui .bg-black{background-color:#000}.swagger-ui .bg-near-black{background-color:#111}.swagger-ui .bg-dark-gray{background-color:#333}.swagger-ui .bg-mid-gray{background-color:#555}.swagger-ui .bg-gray{background-color:#777}.swagger-ui .bg-silver{background-color:#999}.swagger-ui .bg-light-silver{background-color:#aaa}.swagger-ui .bg-moon-gray{background-color:#ccc}.swagger-ui .bg-light-gray{background-color:#eee}.swagger-ui .bg-near-white{background-color:#f4f4f4}.swagger-ui .bg-white{background-color:#fff}.swagger-ui .bg-transparent{background-color:transparent}.swagger-ui .bg-dark-red{background-color:#e7040f}.swagger-ui .bg-red{background-color:#ff4136}.swagger-ui .bg-light-red{background-color:#ff725c}.swagger-ui .bg-orange{background-color:#ff6300}.swagger-ui .bg-gold{background-color:#ffb700}.swagger-ui .bg-yellow{background-color:gold}.swagger-ui .bg-light-yellow{background-color:#fbf1a9}.swagger-ui .bg-purple{background-color:#5e2ca5}.swagger-ui .bg-light-purple{background-color:#a463f2}.swagger-ui .bg-dark-pink{background-color:#d5008f}.swagger-ui .bg-hot-pink{background-color:#ff41b4}.swagger-ui .bg-pink{background-color:#ff80cc}.swagger-ui .bg-light-pink{background-color:#ffa3d7}.swagger-ui .bg-dark-green{background-color:#137752}.swagger-ui .bg-green{background-color:#19a974}.swagger-ui .bg-light-green{background-color:#9eebcf}.swagger-ui .bg-navy{background-color:#001b44}.swagger-ui .bg-dark-blue{background-color:#00449e}.swagger-ui .bg-blue{background-color:#357edd}.swagger-ui .bg-light-blue{background-color:#96ccff}.swagger-ui .bg-lightest-blue{background-color:#cdecff}.swagger-ui .bg-washed-blue{background-color:#f6fffe}.swagger-ui .bg-washed-green{background-color:#e8fdf5}.swagger-ui .bg-washed-yellow{background-color:#fffceb}.swagger-ui .bg-washed-red{background-color:#ffdfdf}.swagger-ui .bg-inherit{background-color:inherit}.swagger-ui .hover-black:focus,.swagger-ui .hover-black:hover{color:#000}.swagger-ui .hover-near-black:focus,.swagger-ui .hover-near-black:hover{color:#111}.swagger-ui .hover-dark-gray:focus,.swagger-ui .hover-dark-gray:hover{color:#333}.swagger-ui .hover-mid-gray:focus,.swagger-ui .hover-mid-gray:hover{color:#555}.swagger-ui .hover-gray:focus,.swagger-ui .hover-gray:hover{color:#777}.swagger-ui .hover-silver:focus,.swagger-ui .hover-silver:hover{color:#999}.swagger-ui .hover-light-silver:focus,.swagger-ui .hover-light-silver:hover{color:#aaa}.swagger-ui .hover-moon-gray:focus,.swagger-ui .hover-moon-gray:hover{color:#ccc}.swagger-ui .hover-light-gray:focus,.swagger-ui .hover-light-gray:hover{color:#eee}.swagger-ui .hover-near-white:focus,.swagger-ui .hover-near-white:hover{color:#f4f4f4}.swagger-ui .hover-white:focus,.swagger-ui .hover-white:hover{color:#fff}.swagger-ui .hover-black-90:focus,.swagger-ui .hover-black-90:hover{color:rgba(0,0,0,.9)}.swagger-ui .hover-black-80:focus,.swagger-ui .hover-black-80:hover{color:rgba(0,0,0,.8)}.swagger-ui .hover-black-70:focus,.swagger-ui .hover-black-70:hover{color:rgba(0,0,0,.7)}.swagger-ui .hover-black-60:focus,.swagger-ui .hover-black-60:hover{color:rgba(0,0,0,.6)}.swagger-ui .hover-black-50:focus,.swagger-ui .hover-black-50:hover{color:rgba(0,0,0,.5)}.swagger-ui .hover-black-40:focus,.swagger-ui .hover-black-40:hover{color:rgba(0,0,0,.4)}.swagger-ui .hover-black-30:focus,.swagger-ui .hover-black-30:hover{color:rgba(0,0,0,.3)}.swagger-ui .hover-black-20:focus,.swagger-ui .hover-black-20:hover{color:rgba(0,0,0,.2)}.swagger-ui .hover-black-10:focus,.swagger-ui .hover-black-10:hover{color:rgba(0,0,0,.1)}.swagger-ui .hover-white-90:focus,.swagger-ui .hover-white-90:hover{color:hsla(0,0%,100%,.9)}.swagger-ui .hover-white-80:focus,.swagger-ui .hover-white-80:hover{color:hsla(0,0%,100%,.8)}.swagger-ui .hover-white-70:focus,.swagger-ui .hover-white-70:hover{color:hsla(0,0%,100%,.7)}.swagger-ui .hover-white-60:focus,.swagger-ui .hover-white-60:hover{color:hsla(0,0%,100%,.6)}.swagger-ui .hover-white-50:focus,.swagger-ui .hover-white-50:hover{color:hsla(0,0%,100%,.5)}.swagger-ui .hover-white-40:focus,.swagger-ui .hover-white-40:hover{color:hsla(0,0%,100%,.4)}.swagger-ui .hover-white-30:focus,.swagger-ui .hover-white-30:hover{color:hsla(0,0%,100%,.3)}.swagger-ui .hover-white-20:focus,.swagger-ui .hover-white-20:hover{color:hsla(0,0%,100%,.2)}.swagger-ui .hover-white-10:focus,.swagger-ui .hover-white-10:hover{color:hsla(0,0%,100%,.1)}.swagger-ui .hover-inherit:focus,.swagger-ui .hover-inherit:hover{color:inherit}.swagger-ui .hover-bg-black:focus,.swagger-ui .hover-bg-black:hover{background-color:#000}.swagger-ui .hover-bg-near-black:focus,.swagger-ui .hover-bg-near-black:hover{background-color:#111}.swagger-ui .hover-bg-dark-gray:focus,.swagger-ui .hover-bg-dark-gray:hover{background-color:#333}.swagger-ui .hover-bg-mid-gray:focus,.swagger-ui .hover-bg-mid-gray:hover{background-color:#555}.swagger-ui .hover-bg-gray:focus,.swagger-ui .hover-bg-gray:hover{background-color:#777}.swagger-ui .hover-bg-silver:focus,.swagger-ui .hover-bg-silver:hover{background-color:#999}.swagger-ui .hover-bg-light-silver:focus,.swagger-ui .hover-bg-light-silver:hover{background-color:#aaa}.swagger-ui .hover-bg-moon-gray:focus,.swagger-ui .hover-bg-moon-gray:hover{background-color:#ccc}.swagger-ui .hover-bg-light-gray:focus,.swagger-ui .hover-bg-light-gray:hover{background-color:#eee}.swagger-ui .hover-bg-near-white:focus,.swagger-ui .hover-bg-near-white:hover{background-color:#f4f4f4}.swagger-ui .hover-bg-white:focus,.swagger-ui .hover-bg-white:hover{background-color:#fff}.swagger-ui .hover-bg-transparent:focus,.swagger-ui .hover-bg-transparent:hover{background-color:transparent}.swagger-ui .hover-bg-black-90:focus,.swagger-ui .hover-bg-black-90:hover{background-color:rgba(0,0,0,.9)}.swagger-ui .hover-bg-black-80:focus,.swagger-ui .hover-bg-black-80:hover{background-color:rgba(0,0,0,.8)}.swagger-ui .hover-bg-black-70:focus,.swagger-ui .hover-bg-black-70:hover{background-color:rgba(0,0,0,.7)}.swagger-ui .hover-bg-black-60:focus,.swagger-ui .hover-bg-black-60:hover{background-color:rgba(0,0,0,.6)}.swagger-ui .hover-bg-black-50:focus,.swagger-ui .hover-bg-black-50:hover{background-color:rgba(0,0,0,.5)}.swagger-ui .hover-bg-black-40:focus,.swagger-ui .hover-bg-black-40:hover{background-color:rgba(0,0,0,.4)}.swagger-ui .hover-bg-black-30:focus,.swagger-ui .hover-bg-black-30:hover{background-color:rgba(0,0,0,.3)}.swagger-ui .hover-bg-black-20:focus,.swagger-ui .hover-bg-black-20:hover{background-color:rgba(0,0,0,.2)}.swagger-ui .hover-bg-black-10:focus,.swagger-ui .hover-bg-black-10:hover{background-color:rgba(0,0,0,.1)}.swagger-ui .hover-bg-white-90:focus,.swagger-ui .hover-bg-white-90:hover{background-color:hsla(0,0%,100%,.9)}.swagger-ui .hover-bg-white-80:focus,.swagger-ui .hover-bg-white-80:hover{background-color:hsla(0,0%,100%,.8)}.swagger-ui .hover-bg-white-70:focus,.swagger-ui .hover-bg-white-70:hover{background-color:hsla(0,0%,100%,.7)}.swagger-ui .hover-bg-white-60:focus,.swagger-ui .hover-bg-white-60:hover{background-color:hsla(0,0%,100%,.6)}.swagger-ui .hover-bg-white-50:focus,.swagger-ui .hover-bg-white-50:hover{background-color:hsla(0,0%,100%,.5)}.swagger-ui .hover-bg-white-40:focus,.swagger-ui .hover-bg-white-40:hover{background-color:hsla(0,0%,100%,.4)}.swagger-ui .hover-bg-white-30:focus,.swagger-ui .hover-bg-white-30:hover{background-color:hsla(0,0%,100%,.3)}.swagger-ui .hover-bg-white-20:focus,.swagger-ui .hover-bg-white-20:hover{background-color:hsla(0,0%,100%,.2)}.swagger-ui .hover-bg-white-10:focus,.swagger-ui .hover-bg-white-10:hover{background-color:hsla(0,0%,100%,.1)}.swagger-ui .hover-dark-red:focus,.swagger-ui .hover-dark-red:hover{color:#e7040f}.swagger-ui .hover-red:focus,.swagger-ui .hover-red:hover{color:#ff4136}.swagger-ui .hover-light-red:focus,.swagger-ui .hover-light-red:hover{color:#ff725c}.swagger-ui .hover-orange:focus,.swagger-ui .hover-orange:hover{color:#ff6300}.swagger-ui .hover-gold:focus,.swagger-ui .hover-gold:hover{color:#ffb700}.swagger-ui .hover-yellow:focus,.swagger-ui .hover-yellow:hover{color:gold}.swagger-ui .hover-light-yellow:focus,.swagger-ui .hover-light-yellow:hover{color:#fbf1a9}.swagger-ui .hover-purple:focus,.swagger-ui .hover-purple:hover{color:#5e2ca5}.swagger-ui .hover-light-purple:focus,.swagger-ui .hover-light-purple:hover{color:#a463f2}.swagger-ui .hover-dark-pink:focus,.swagger-ui .hover-dark-pink:hover{color:#d5008f}.swagger-ui .hover-hot-pink:focus,.swagger-ui .hover-hot-pink:hover{color:#ff41b4}.swagger-ui .hover-pink:focus,.swagger-ui .hover-pink:hover{color:#ff80cc}.swagger-ui .hover-light-pink:focus,.swagger-ui .hover-light-pink:hover{color:#ffa3d7}.swagger-ui .hover-dark-green:focus,.swagger-ui .hover-dark-green:hover{color:#137752}.swagger-ui .hover-green:focus,.swagger-ui .hover-green:hover{color:#19a974}.swagger-ui .hover-light-green:focus,.swagger-ui .hover-light-green:hover{color:#9eebcf}.swagger-ui .hover-navy:focus,.swagger-ui .hover-navy:hover{color:#001b44}.swagger-ui .hover-dark-blue:focus,.swagger-ui .hover-dark-blue:hover{color:#00449e}.swagger-ui .hover-blue:focus,.swagger-ui .hover-blue:hover{color:#357edd}.swagger-ui .hover-light-blue:focus,.swagger-ui .hover-light-blue:hover{color:#96ccff}.swagger-ui .hover-lightest-blue:focus,.swagger-ui .hover-lightest-blue:hover{color:#cdecff}.swagger-ui .hover-washed-blue:focus,.swagger-ui .hover-washed-blue:hover{color:#f6fffe}.swagger-ui .hover-washed-green:focus,.swagger-ui .hover-washed-green:hover{color:#e8fdf5}.swagger-ui .hover-washed-yellow:focus,.swagger-ui .hover-washed-yellow:hover{color:#fffceb}.swagger-ui .hover-washed-red:focus,.swagger-ui .hover-washed-red:hover{color:#ffdfdf}.swagger-ui .hover-bg-dark-red:focus,.swagger-ui .hover-bg-dark-red:hover{background-color:#e7040f}.swagger-ui .hover-bg-red:focus,.swagger-ui .hover-bg-red:hover{background-color:#ff4136}.swagger-ui .hover-bg-light-red:focus,.swagger-ui .hover-bg-light-red:hover{background-color:#ff725c}.swagger-ui .hover-bg-orange:focus,.swagger-ui .hover-bg-orange:hover{background-color:#ff6300}.swagger-ui .hover-bg-gold:focus,.swagger-ui .hover-bg-gold:hover{background-color:#ffb700}.swagger-ui .hover-bg-yellow:focus,.swagger-ui .hover-bg-yellow:hover{background-color:gold}.swagger-ui .hover-bg-light-yellow:focus,.swagger-ui .hover-bg-light-yellow:hover{background-color:#fbf1a9}.swagger-ui .hover-bg-purple:focus,.swagger-ui .hover-bg-purple:hover{background-color:#5e2ca5}.swagger-ui .hover-bg-light-purple:focus,.swagger-ui .hover-bg-light-purple:hover{background-color:#a463f2}.swagger-ui .hover-bg-dark-pink:focus,.swagger-ui .hover-bg-dark-pink:hover{background-color:#d5008f}.swagger-ui .hover-bg-hot-pink:focus,.swagger-ui .hover-bg-hot-pink:hover{background-color:#ff41b4}.swagger-ui .hover-bg-pink:focus,.swagger-ui .hover-bg-pink:hover{background-color:#ff80cc}.swagger-ui .hover-bg-light-pink:focus,.swagger-ui .hover-bg-light-pink:hover{background-color:#ffa3d7}.swagger-ui .hover-bg-dark-green:focus,.swagger-ui .hover-bg-dark-green:hover{background-color:#137752}.swagger-ui .hover-bg-green:focus,.swagger-ui .hover-bg-green:hover{background-color:#19a974}.swagger-ui .hover-bg-light-green:focus,.swagger-ui .hover-bg-light-green:hover{background-color:#9eebcf}.swagger-ui .hover-bg-navy:focus,.swagger-ui .hover-bg-navy:hover{background-color:#001b44}.swagger-ui .hover-bg-dark-blue:focus,.swagger-ui .hover-bg-dark-blue:hover{background-color:#00449e}.swagger-ui .hover-bg-blue:focus,.swagger-ui .hover-bg-blue:hover{background-color:#357edd}.swagger-ui .hover-bg-light-blue:focus,.swagger-ui .hover-bg-light-blue:hover{background-color:#96ccff}.swagger-ui .hover-bg-lightest-blue:focus,.swagger-ui .hover-bg-lightest-blue:hover{background-color:#cdecff}.swagger-ui .hover-bg-washed-blue:focus,.swagger-ui .hover-bg-washed-blue:hover{background-color:#f6fffe}.swagger-ui .hover-bg-washed-green:focus,.swagger-ui .hover-bg-washed-green:hover{background-color:#e8fdf5}.swagger-ui .hover-bg-washed-yellow:focus,.swagger-ui .hover-bg-washed-yellow:hover{background-color:#fffceb}.swagger-ui .hover-bg-washed-red:focus,.swagger-ui .hover-bg-washed-red:hover{background-color:#ffdfdf}.swagger-ui .hover-bg-inherit:focus,.swagger-ui .hover-bg-inherit:hover{background-color:inherit}.swagger-ui .pa0{padding:0}.swagger-ui .pa1{padding:.25rem}.swagger-ui .pa2{padding:.5rem}.swagger-ui .pa3{padding:1rem}.swagger-ui .pa4{padding:2rem}.swagger-ui .pa5{padding:4rem}.swagger-ui .pa6{padding:8rem}.swagger-ui .pa7{padding:16rem}.swagger-ui .pl0{padding-left:0}.swagger-ui .pl1{padding-left:.25rem}.swagger-ui .pl2{padding-left:.5rem}.swagger-ui .pl3{padding-left:1rem}.swagger-ui .pl4{padding-left:2rem}.swagger-ui .pl5{padding-left:4rem}.swagger-ui .pl6{padding-left:8rem}.swagger-ui .pl7{padding-left:16rem}.swagger-ui .pr0{padding-right:0}.swagger-ui .pr1{padding-right:.25rem}.swagger-ui .pr2{padding-right:.5rem}.swagger-ui .pr3{padding-right:1rem}.swagger-ui .pr4{padding-right:2rem}.swagger-ui .pr5{padding-right:4rem}.swagger-ui .pr6{padding-right:8rem}.swagger-ui .pr7{padding-right:16rem}.swagger-ui .pb0{padding-bottom:0}.swagger-ui .pb1{padding-bottom:.25rem}.swagger-ui .pb2{padding-bottom:.5rem}.swagger-ui .pb3{padding-bottom:1rem}.swagger-ui .pb4{padding-bottom:2rem}.swagger-ui .pb5{padding-bottom:4rem}.swagger-ui .pb6{padding-bottom:8rem}.swagger-ui .pb7{padding-bottom:16rem}.swagger-ui .pt0{padding-top:0}.swagger-ui .pt1{padding-top:.25rem}.swagger-ui .pt2{padding-top:.5rem}.swagger-ui .pt3{padding-top:1rem}.swagger-ui .pt4{padding-top:2rem}.swagger-ui .pt5{padding-top:4rem}.swagger-ui .pt6{padding-top:8rem}.swagger-ui .pt7{padding-top:16rem}.swagger-ui .pv0{padding-top:0;padding-bottom:0}.swagger-ui .pv1{padding-top:.25rem;padding-bottom:.25rem}.swagger-ui .pv2{padding-top:.5rem;padding-bottom:.5rem}.swagger-ui .pv3{padding-top:1rem;padding-bottom:1rem}.swagger-ui .pv4{padding-top:2rem;padding-bottom:2rem}.swagger-ui .pv5{padding-top:4rem;padding-bottom:4rem}.swagger-ui .pv6{padding-top:8rem;padding-bottom:8rem}.swagger-ui .pv7{padding-top:16rem;padding-bottom:16rem}.swagger-ui .ph0{padding-left:0;padding-right:0}.swagger-ui .ph1{padding-left:.25rem;padding-right:.25rem}.swagger-ui .ph2{padding-left:.5rem;padding-right:.5rem}.swagger-ui .ph3{padding-left:1rem;padding-right:1rem}.swagger-ui .ph4{padding-left:2rem;padding-right:2rem}.swagger-ui .ph5{padding-left:4rem;padding-right:4rem}.swagger-ui .ph6{padding-left:8rem;padding-right:8rem}.swagger-ui .ph7{padding-left:16rem;padding-right:16rem}.swagger-ui .ma0{margin:0}.swagger-ui .ma1{margin:.25rem}.swagger-ui .ma2{margin:.5rem}.swagger-ui .ma3{margin:1rem}.swagger-ui .ma4{margin:2rem}.swagger-ui .ma5{margin:4rem}.swagger-ui .ma6{margin:8rem}.swagger-ui .ma7{margin:16rem}.swagger-ui .ml0{margin-left:0}.swagger-ui .ml1{margin-left:.25rem}.swagger-ui .ml2{margin-left:.5rem}.swagger-ui .ml3{margin-left:1rem}.swagger-ui .ml4{margin-left:2rem}.swagger-ui .ml5{margin-left:4rem}.swagger-ui .ml6{margin-left:8rem}.swagger-ui .ml7{margin-left:16rem}.swagger-ui .mr0{margin-right:0}.swagger-ui .mr1{margin-right:.25rem}.swagger-ui .mr2{margin-right:.5rem}.swagger-ui .mr3{margin-right:1rem}.swagger-ui .mr4{margin-right:2rem}.swagger-ui .mr5{margin-right:4rem}.swagger-ui .mr6{margin-right:8rem}.swagger-ui .mr7{margin-right:16rem}.swagger-ui .mb0{margin-bottom:0}.swagger-ui .mb1{margin-bottom:.25rem}.swagger-ui .mb2{margin-bottom:.5rem}.swagger-ui .mb3{margin-bottom:1rem}.swagger-ui .mb4{margin-bottom:2rem}.swagger-ui .mb5{margin-bottom:4rem}.swagger-ui .mb6{margin-bottom:8rem}.swagger-ui .mb7{margin-bottom:16rem}.swagger-ui .mt0{margin-top:0}.swagger-ui .mt1{margin-top:.25rem}.swagger-ui .mt2{margin-top:.5rem}.swagger-ui .mt3{margin-top:1rem}.swagger-ui .mt4{margin-top:2rem}.swagger-ui .mt5{margin-top:4rem}.swagger-ui .mt6{margin-top:8rem}.swagger-ui .mt7{margin-top:16rem}.swagger-ui .mv0{margin-top:0;margin-bottom:0}.swagger-ui .mv1{margin-top:.25rem;margin-bottom:.25rem}.swagger-ui .mv2{margin-top:.5rem;margin-bottom:.5rem}.swagger-ui .mv3{margin-top:1rem;margin-bottom:1rem}.swagger-ui .mv4{margin-top:2rem;margin-bottom:2rem}.swagger-ui .mv5{margin-top:4rem;margin-bottom:4rem}.swagger-ui .mv6{margin-top:8rem;margin-bottom:8rem}.swagger-ui .mv7{margin-top:16rem;margin-bottom:16rem}.swagger-ui .mh0{margin-left:0;margin-right:0}.swagger-ui .mh1{margin-left:.25rem;margin-right:.25rem}.swagger-ui .mh2{margin-left:.5rem;margin-right:.5rem}.swagger-ui .mh3{margin-left:1rem;margin-right:1rem}.swagger-ui .mh4{margin-left:2rem;margin-right:2rem}.swagger-ui .mh5{margin-left:4rem;margin-right:4rem}.swagger-ui .mh6{margin-left:8rem;margin-right:8rem}.swagger-ui .mh7{margin-left:16rem;margin-right:16rem}@media screen and (min-width:30em){.swagger-ui .pa0-ns{padding:0}.swagger-ui .pa1-ns{padding:.25rem}.swagger-ui .pa2-ns{padding:.5rem}.swagger-ui .pa3-ns{padding:1rem}.swagger-ui .pa4-ns{padding:2rem}.swagger-ui .pa5-ns{padding:4rem}.swagger-ui .pa6-ns{padding:8rem}.swagger-ui .pa7-ns{padding:16rem}.swagger-ui .pl0-ns{padding-left:0}.swagger-ui .pl1-ns{padding-left:.25rem}.swagger-ui .pl2-ns{padding-left:.5rem}.swagger-ui .pl3-ns{padding-left:1rem}.swagger-ui .pl4-ns{padding-left:2rem}.swagger-ui .pl5-ns{padding-left:4rem}.swagger-ui .pl6-ns{padding-left:8rem}.swagger-ui .pl7-ns{padding-left:16rem}.swagger-ui .pr0-ns{padding-right:0}.swagger-ui .pr1-ns{padding-right:.25rem}.swagger-ui .pr2-ns{padding-right:.5rem}.swagger-ui .pr3-ns{padding-right:1rem}.swagger-ui .pr4-ns{padding-right:2rem}.swagger-ui .pr5-ns{padding-right:4rem}.swagger-ui .pr6-ns{padding-right:8rem}.swagger-ui .pr7-ns{padding-right:16rem}.swagger-ui .pb0-ns{padding-bottom:0}.swagger-ui .pb1-ns{padding-bottom:.25rem}.swagger-ui .pb2-ns{padding-bottom:.5rem}.swagger-ui .pb3-ns{padding-bottom:1rem}.swagger-ui .pb4-ns{padding-bottom:2rem}.swagger-ui .pb5-ns{padding-bottom:4rem}.swagger-ui .pb6-ns{padding-bottom:8rem}.swagger-ui .pb7-ns{padding-bottom:16rem}.swagger-ui .pt0-ns{padding-top:0}.swagger-ui .pt1-ns{padding-top:.25rem}.swagger-ui .pt2-ns{padding-top:.5rem}.swagger-ui .pt3-ns{padding-top:1rem}.swagger-ui .pt4-ns{padding-top:2rem}.swagger-ui .pt5-ns{padding-top:4rem}.swagger-ui .pt6-ns{padding-top:8rem}.swagger-ui .pt7-ns{padding-top:16rem}.swagger-ui .pv0-ns{padding-top:0;padding-bottom:0}.swagger-ui .pv1-ns{padding-top:.25rem;padding-bottom:.25rem}.swagger-ui .pv2-ns{padding-top:.5rem;padding-bottom:.5rem}.swagger-ui .pv3-ns{padding-top:1rem;padding-bottom:1rem}.swagger-ui .pv4-ns{padding-top:2rem;padding-bottom:2rem}.swagger-ui .pv5-ns{padding-top:4rem;padding-bottom:4rem}.swagger-ui .pv6-ns{padding-top:8rem;padding-bottom:8rem}.swagger-ui .pv7-ns{padding-top:16rem;padding-bottom:16rem}.swagger-ui .ph0-ns{padding-left:0;padding-right:0}.swagger-ui .ph1-ns{padding-left:.25rem;padding-right:.25rem}.swagger-ui .ph2-ns{padding-left:.5rem;padding-right:.5rem}.swagger-ui .ph3-ns{padding-left:1rem;padding-right:1rem}.swagger-ui .ph4-ns{padding-left:2rem;padding-right:2rem}.swagger-ui .ph5-ns{padding-left:4rem;padding-right:4rem}.swagger-ui .ph6-ns{padding-left:8rem;padding-right:8rem}.swagger-ui .ph7-ns{padding-left:16rem;padding-right:16rem}.swagger-ui .ma0-ns{margin:0}.swagger-ui .ma1-ns{margin:.25rem}.swagger-ui .ma2-ns{margin:.5rem}.swagger-ui .ma3-ns{margin:1rem}.swagger-ui .ma4-ns{margin:2rem}.swagger-ui .ma5-ns{margin:4rem}.swagger-ui .ma6-ns{margin:8rem}.swagger-ui .ma7-ns{margin:16rem}.swagger-ui .ml0-ns{margin-left:0}.swagger-ui .ml1-ns{margin-left:.25rem}.swagger-ui .ml2-ns{margin-left:.5rem}.swagger-ui .ml3-ns{margin-left:1rem}.swagger-ui .ml4-ns{margin-left:2rem}.swagger-ui .ml5-ns{margin-left:4rem}.swagger-ui .ml6-ns{margin-left:8rem}.swagger-ui .ml7-ns{margin-left:16rem}.swagger-ui .mr0-ns{margin-right:0}.swagger-ui .mr1-ns{margin-right:.25rem}.swagger-ui .mr2-ns{margin-right:.5rem}.swagger-ui .mr3-ns{margin-right:1rem}.swagger-ui .mr4-ns{margin-right:2rem}.swagger-ui .mr5-ns{margin-right:4rem}.swagger-ui .mr6-ns{margin-right:8rem}.swagger-ui .mr7-ns{margin-right:16rem}.swagger-ui .mb0-ns{margin-bottom:0}.swagger-ui .mb1-ns{margin-bottom:.25rem}.swagger-ui .mb2-ns{margin-bottom:.5rem}.swagger-ui .mb3-ns{margin-bottom:1rem}.swagger-ui .mb4-ns{margin-bottom:2rem}.swagger-ui .mb5-ns{margin-bottom:4rem}.swagger-ui .mb6-ns{margin-bottom:8rem}.swagger-ui .mb7-ns{margin-bottom:16rem}.swagger-ui .mt0-ns{margin-top:0}.swagger-ui .mt1-ns{margin-top:.25rem}.swagger-ui .mt2-ns{margin-top:.5rem}.swagger-ui .mt3-ns{margin-top:1rem}.swagger-ui .mt4-ns{margin-top:2rem}.swagger-ui .mt5-ns{margin-top:4rem}.swagger-ui .mt6-ns{margin-top:8rem}.swagger-ui .mt7-ns{margin-top:16rem}.swagger-ui .mv0-ns{margin-top:0;margin-bottom:0}.swagger-ui .mv1-ns{margin-top:.25rem;margin-bottom:.25rem}.swagger-ui .mv2-ns{margin-top:.5rem;margin-bottom:.5rem}.swagger-ui .mv3-ns{margin-top:1rem;margin-bottom:1rem}.swagger-ui .mv4-ns{margin-top:2rem;margin-bottom:2rem}.swagger-ui .mv5-ns{margin-top:4rem;margin-bottom:4rem}.swagger-ui .mv6-ns{margin-top:8rem;margin-bottom:8rem}.swagger-ui .mv7-ns{margin-top:16rem;margin-bottom:16rem}.swagger-ui .mh0-ns{margin-left:0;margin-right:0}.swagger-ui .mh1-ns{margin-left:.25rem;margin-right:.25rem}.swagger-ui .mh2-ns{margin-left:.5rem;margin-right:.5rem}.swagger-ui .mh3-ns{margin-left:1rem;margin-right:1rem}.swagger-ui .mh4-ns{margin-left:2rem;margin-right:2rem}.swagger-ui .mh5-ns{margin-left:4rem;margin-right:4rem}.swagger-ui .mh6-ns{margin-left:8rem;margin-right:8rem}.swagger-ui .mh7-ns{margin-left:16rem;margin-right:16rem}}@media screen and (min-width:30em) and (max-width:60em){.swagger-ui .pa0-m{padding:0}.swagger-ui .pa1-m{padding:.25rem}.swagger-ui .pa2-m{padding:.5rem}.swagger-ui .pa3-m{padding:1rem}.swagger-ui .pa4-m{padding:2rem}.swagger-ui .pa5-m{padding:4rem}.swagger-ui .pa6-m{padding:8rem}.swagger-ui .pa7-m{padding:16rem}.swagger-ui .pl0-m{padding-left:0}.swagger-ui .pl1-m{padding-left:.25rem}.swagger-ui .pl2-m{padding-left:.5rem}.swagger-ui .pl3-m{padding-left:1rem}.swagger-ui .pl4-m{padding-left:2rem}.swagger-ui .pl5-m{padding-left:4rem}.swagger-ui .pl6-m{padding-left:8rem}.swagger-ui .pl7-m{padding-left:16rem}.swagger-ui .pr0-m{padding-right:0}.swagger-ui .pr1-m{padding-right:.25rem}.swagger-ui .pr2-m{padding-right:.5rem}.swagger-ui .pr3-m{padding-right:1rem}.swagger-ui .pr4-m{padding-right:2rem}.swagger-ui .pr5-m{padding-right:4rem}.swagger-ui .pr6-m{padding-right:8rem}.swagger-ui .pr7-m{padding-right:16rem}.swagger-ui .pb0-m{padding-bottom:0}.swagger-ui .pb1-m{padding-bottom:.25rem}.swagger-ui .pb2-m{padding-bottom:.5rem}.swagger-ui .pb3-m{padding-bottom:1rem}.swagger-ui .pb4-m{padding-bottom:2rem}.swagger-ui .pb5-m{padding-bottom:4rem}.swagger-ui .pb6-m{padding-bottom:8rem}.swagger-ui .pb7-m{padding-bottom:16rem}.swagger-ui .pt0-m{padding-top:0}.swagger-ui .pt1-m{padding-top:.25rem}.swagger-ui .pt2-m{padding-top:.5rem}.swagger-ui .pt3-m{padding-top:1rem}.swagger-ui .pt4-m{padding-top:2rem}.swagger-ui .pt5-m{padding-top:4rem}.swagger-ui .pt6-m{padding-top:8rem}.swagger-ui .pt7-m{padding-top:16rem}.swagger-ui .pv0-m{padding-top:0;padding-bottom:0}.swagger-ui .pv1-m{padding-top:.25rem;padding-bottom:.25rem}.swagger-ui .pv2-m{padding-top:.5rem;padding-bottom:.5rem}.swagger-ui .pv3-m{padding-top:1rem;padding-bottom:1rem}.swagger-ui .pv4-m{padding-top:2rem;padding-bottom:2rem}.swagger-ui .pv5-m{padding-top:4rem;padding-bottom:4rem}.swagger-ui .pv6-m{padding-top:8rem;padding-bottom:8rem}.swagger-ui .pv7-m{padding-top:16rem;padding-bottom:16rem}.swagger-ui .ph0-m{padding-left:0;padding-right:0}.swagger-ui .ph1-m{padding-left:.25rem;padding-right:.25rem}.swagger-ui .ph2-m{padding-left:.5rem;padding-right:.5rem}.swagger-ui .ph3-m{padding-left:1rem;padding-right:1rem}.swagger-ui .ph4-m{padding-left:2rem;padding-right:2rem}.swagger-ui .ph5-m{padding-left:4rem;padding-right:4rem}.swagger-ui .ph6-m{padding-left:8rem;padding-right:8rem}.swagger-ui .ph7-m{padding-left:16rem;padding-right:16rem}.swagger-ui .ma0-m{margin:0}.swagger-ui .ma1-m{margin:.25rem}.swagger-ui .ma2-m{margin:.5rem}.swagger-ui .ma3-m{margin:1rem}.swagger-ui .ma4-m{margin:2rem}.swagger-ui .ma5-m{margin:4rem}.swagger-ui .ma6-m{margin:8rem}.swagger-ui .ma7-m{margin:16rem}.swagger-ui .ml0-m{margin-left:0}.swagger-ui .ml1-m{margin-left:.25rem}.swagger-ui .ml2-m{margin-left:.5rem}.swagger-ui .ml3-m{margin-left:1rem}.swagger-ui .ml4-m{margin-left:2rem}.swagger-ui .ml5-m{margin-left:4rem}.swagger-ui .ml6-m{margin-left:8rem}.swagger-ui .ml7-m{margin-left:16rem}.swagger-ui .mr0-m{margin-right:0}.swagger-ui .mr1-m{margin-right:.25rem}.swagger-ui .mr2-m{margin-right:.5rem}.swagger-ui .mr3-m{margin-right:1rem}.swagger-ui .mr4-m{margin-right:2rem}.swagger-ui .mr5-m{margin-right:4rem}.swagger-ui .mr6-m{margin-right:8rem}.swagger-ui .mr7-m{margin-right:16rem}.swagger-ui .mb0-m{margin-bottom:0}.swagger-ui .mb1-m{margin-bottom:.25rem}.swagger-ui .mb2-m{margin-bottom:.5rem}.swagger-ui .mb3-m{margin-bottom:1rem}.swagger-ui .mb4-m{margin-bottom:2rem}.swagger-ui .mb5-m{margin-bottom:4rem}.swagger-ui .mb6-m{margin-bottom:8rem}.swagger-ui .mb7-m{margin-bottom:16rem}.swagger-ui .mt0-m{margin-top:0}.swagger-ui .mt1-m{margin-top:.25rem}.swagger-ui .mt2-m{margin-top:.5rem}.swagger-ui .mt3-m{margin-top:1rem}.swagger-ui .mt4-m{margin-top:2rem}.swagger-ui .mt5-m{margin-top:4rem}.swagger-ui .mt6-m{margin-top:8rem}.swagger-ui .mt7-m{margin-top:16rem}.swagger-ui .mv0-m{margin-top:0;margin-bottom:0}.swagger-ui .mv1-m{margin-top:.25rem;margin-bottom:.25rem}.swagger-ui .mv2-m{margin-top:.5rem;margin-bottom:.5rem}.swagger-ui .mv3-m{margin-top:1rem;margin-bottom:1rem}.swagger-ui .mv4-m{margin-top:2rem;margin-bottom:2rem}.swagger-ui .mv5-m{margin-top:4rem;margin-bottom:4rem}.swagger-ui .mv6-m{margin-top:8rem;margin-bottom:8rem}.swagger-ui .mv7-m{margin-top:16rem;margin-bottom:16rem}.swagger-ui .mh0-m{margin-left:0;margin-right:0}.swagger-ui .mh1-m{margin-left:.25rem;margin-right:.25rem}.swagger-ui .mh2-m{margin-left:.5rem;margin-right:.5rem}.swagger-ui .mh3-m{margin-left:1rem;margin-right:1rem}.swagger-ui .mh4-m{margin-left:2rem;margin-right:2rem}.swagger-ui .mh5-m{margin-left:4rem;margin-right:4rem}.swagger-ui .mh6-m{margin-left:8rem;margin-right:8rem}.swagger-ui .mh7-m{margin-left:16rem;margin-right:16rem}}@media screen and (min-width:60em){.swagger-ui .pa0-l{padding:0}.swagger-ui .pa1-l{padding:.25rem}.swagger-ui .pa2-l{padding:.5rem}.swagger-ui .pa3-l{padding:1rem}.swagger-ui .pa4-l{padding:2rem}.swagger-ui .pa5-l{padding:4rem}.swagger-ui .pa6-l{padding:8rem}.swagger-ui .pa7-l{padding:16rem}.swagger-ui .pl0-l{padding-left:0}.swagger-ui .pl1-l{padding-left:.25rem}.swagger-ui .pl2-l{padding-left:.5rem}.swagger-ui .pl3-l{padding-left:1rem}.swagger-ui .pl4-l{padding-left:2rem}.swagger-ui .pl5-l{padding-left:4rem}.swagger-ui .pl6-l{padding-left:8rem}.swagger-ui .pl7-l{padding-left:16rem}.swagger-ui .pr0-l{padding-right:0}.swagger-ui .pr1-l{padding-right:.25rem}.swagger-ui .pr2-l{padding-right:.5rem}.swagger-ui .pr3-l{padding-right:1rem}.swagger-ui .pr4-l{padding-right:2rem}.swagger-ui .pr5-l{padding-right:4rem}.swagger-ui .pr6-l{padding-right:8rem}.swagger-ui .pr7-l{padding-right:16rem}.swagger-ui .pb0-l{padding-bottom:0}.swagger-ui .pb1-l{padding-bottom:.25rem}.swagger-ui .pb2-l{padding-bottom:.5rem}.swagger-ui .pb3-l{padding-bottom:1rem}.swagger-ui .pb4-l{padding-bottom:2rem}.swagger-ui .pb5-l{padding-bottom:4rem}.swagger-ui .pb6-l{padding-bottom:8rem}.swagger-ui .pb7-l{padding-bottom:16rem}.swagger-ui .pt0-l{padding-top:0}.swagger-ui .pt1-l{padding-top:.25rem}.swagger-ui .pt2-l{padding-top:.5rem}.swagger-ui .pt3-l{padding-top:1rem}.swagger-ui .pt4-l{padding-top:2rem}.swagger-ui .pt5-l{padding-top:4rem}.swagger-ui .pt6-l{padding-top:8rem}.swagger-ui .pt7-l{padding-top:16rem}.swagger-ui .pv0-l{padding-top:0;padding-bottom:0}.swagger-ui .pv1-l{padding-top:.25rem;padding-bottom:.25rem}.swagger-ui .pv2-l{padding-top:.5rem;padding-bottom:.5rem}.swagger-ui .pv3-l{padding-top:1rem;padding-bottom:1rem}.swagger-ui .pv4-l{padding-top:2rem;padding-bottom:2rem}.swagger-ui .pv5-l{padding-top:4rem;padding-bottom:4rem}.swagger-ui .pv6-l{padding-top:8rem;padding-bottom:8rem}.swagger-ui .pv7-l{padding-top:16rem;padding-bottom:16rem}.swagger-ui .ph0-l{padding-left:0;padding-right:0}.swagger-ui .ph1-l{padding-left:.25rem;padding-right:.25rem}.swagger-ui .ph2-l{padding-left:.5rem;padding-right:.5rem}.swagger-ui .ph3-l{padding-left:1rem;padding-right:1rem}.swagger-ui .ph4-l{padding-left:2rem;padding-right:2rem}.swagger-ui .ph5-l{padding-left:4rem;padding-right:4rem}.swagger-ui .ph6-l{padding-left:8rem;padding-right:8rem}.swagger-ui .ph7-l{padding-left:16rem;padding-right:16rem}.swagger-ui .ma0-l{margin:0}.swagger-ui .ma1-l{margin:.25rem}.swagger-ui .ma2-l{margin:.5rem}.swagger-ui .ma3-l{margin:1rem}.swagger-ui .ma4-l{margin:2rem}.swagger-ui .ma5-l{margin:4rem}.swagger-ui .ma6-l{margin:8rem}.swagger-ui .ma7-l{margin:16rem}.swagger-ui .ml0-l{margin-left:0}.swagger-ui .ml1-l{margin-left:.25rem}.swagger-ui .ml2-l{margin-left:.5rem}.swagger-ui .ml3-l{margin-left:1rem}.swagger-ui .ml4-l{margin-left:2rem}.swagger-ui .ml5-l{margin-left:4rem}.swagger-ui .ml6-l{margin-left:8rem}.swagger-ui .ml7-l{margin-left:16rem}.swagger-ui .mr0-l{margin-right:0}.swagger-ui .mr1-l{margin-right:.25rem}.swagger-ui .mr2-l{margin-right:.5rem}.swagger-ui .mr3-l{margin-right:1rem}.swagger-ui .mr4-l{margin-right:2rem}.swagger-ui .mr5-l{margin-right:4rem}.swagger-ui .mr6-l{margin-right:8rem}.swagger-ui .mr7-l{margin-right:16rem}.swagger-ui .mb0-l{margin-bottom:0}.swagger-ui .mb1-l{margin-bottom:.25rem}.swagger-ui .mb2-l{margin-bottom:.5rem}.swagger-ui .mb3-l{margin-bottom:1rem}.swagger-ui .mb4-l{margin-bottom:2rem}.swagger-ui .mb5-l{margin-bottom:4rem}.swagger-ui .mb6-l{margin-bottom:8rem}.swagger-ui .mb7-l{margin-bottom:16rem}.swagger-ui .mt0-l{margin-top:0}.swagger-ui .mt1-l{margin-top:.25rem}.swagger-ui .mt2-l{margin-top:.5rem}.swagger-ui .mt3-l{margin-top:1rem}.swagger-ui .mt4-l{margin-top:2rem}.swagger-ui .mt5-l{margin-top:4rem}.swagger-ui .mt6-l{margin-top:8rem}.swagger-ui .mt7-l{margin-top:16rem}.swagger-ui .mv0-l{margin-top:0;margin-bottom:0}.swagger-ui .mv1-l{margin-top:.25rem;margin-bottom:.25rem}.swagger-ui .mv2-l{margin-top:.5rem;margin-bottom:.5rem}.swagger-ui .mv3-l{margin-top:1rem;margin-bottom:1rem}.swagger-ui .mv4-l{margin-top:2rem;margin-bottom:2rem}.swagger-ui .mv5-l{margin-top:4rem;margin-bottom:4rem}.swagger-ui .mv6-l{margin-top:8rem;margin-bottom:8rem}.swagger-ui .mv7-l{margin-top:16rem;margin-bottom:16rem}.swagger-ui .mh0-l{margin-left:0;margin-right:0}.swagger-ui .mh1-l{margin-left:.25rem;margin-right:.25rem}.swagger-ui .mh2-l{margin-left:.5rem;margin-right:.5rem}.swagger-ui .mh3-l{margin-left:1rem;margin-right:1rem}.swagger-ui .mh4-l{margin-left:2rem;margin-right:2rem}.swagger-ui .mh5-l{margin-left:4rem;margin-right:4rem}.swagger-ui .mh6-l{margin-left:8rem;margin-right:8rem}.swagger-ui .mh7-l{margin-left:16rem;margin-right:16rem}}.swagger-ui .na1{margin:-.25rem}.swagger-ui .na2{margin:-.5rem}.swagger-ui .na3{margin:-1rem}.swagger-ui .na4{margin:-2rem}.swagger-ui .na5{margin:-4rem}.swagger-ui .na6{margin:-8rem}.swagger-ui .na7{margin:-16rem}.swagger-ui .nl1{margin-left:-.25rem}.swagger-ui .nl2{margin-left:-.5rem}.swagger-ui .nl3{margin-left:-1rem}.swagger-ui .nl4{margin-left:-2rem}.swagger-ui .nl5{margin-left:-4rem}.swagger-ui .nl6{margin-left:-8rem}.swagger-ui .nl7{margin-left:-16rem}.swagger-ui .nr1{margin-right:-.25rem}.swagger-ui .nr2{margin-right:-.5rem}.swagger-ui .nr3{margin-right:-1rem}.swagger-ui .nr4{margin-right:-2rem}.swagger-ui .nr5{margin-right:-4rem}.swagger-ui .nr6{margin-right:-8rem}.swagger-ui .nr7{margin-right:-16rem}.swagger-ui .nb1{margin-bottom:-.25rem}.swagger-ui .nb2{margin-bottom:-.5rem}.swagger-ui .nb3{margin-bottom:-1rem}.swagger-ui .nb4{margin-bottom:-2rem}.swagger-ui .nb5{margin-bottom:-4rem}.swagger-ui .nb6{margin-bottom:-8rem}.swagger-ui .nb7{margin-bottom:-16rem}.swagger-ui .nt1{margin-top:-.25rem}.swagger-ui .nt2{margin-top:-.5rem}.swagger-ui .nt3{margin-top:-1rem}.swagger-ui .nt4{margin-top:-2rem}.swagger-ui .nt5{margin-top:-4rem}.swagger-ui .nt6{margin-top:-8rem}.swagger-ui .nt7{margin-top:-16rem}@media screen and (min-width:30em){.swagger-ui .na1-ns{margin:-.25rem}.swagger-ui .na2-ns{margin:-.5rem}.swagger-ui .na3-ns{margin:-1rem}.swagger-ui .na4-ns{margin:-2rem}.swagger-ui .na5-ns{margin:-4rem}.swagger-ui .na6-ns{margin:-8rem}.swagger-ui .na7-ns{margin:-16rem}.swagger-ui .nl1-ns{margin-left:-.25rem}.swagger-ui .nl2-ns{margin-left:-.5rem}.swagger-ui .nl3-ns{margin-left:-1rem}.swagger-ui .nl4-ns{margin-left:-2rem}.swagger-ui .nl5-ns{margin-left:-4rem}.swagger-ui .nl6-ns{margin-left:-8rem}.swagger-ui .nl7-ns{margin-left:-16rem}.swagger-ui .nr1-ns{margin-right:-.25rem}.swagger-ui .nr2-ns{margin-right:-.5rem}.swagger-ui .nr3-ns{margin-right:-1rem}.swagger-ui .nr4-ns{margin-right:-2rem}.swagger-ui .nr5-ns{margin-right:-4rem}.swagger-ui .nr6-ns{margin-right:-8rem}.swagger-ui .nr7-ns{margin-right:-16rem}.swagger-ui .nb1-ns{margin-bottom:-.25rem}.swagger-ui .nb2-ns{margin-bottom:-.5rem}.swagger-ui .nb3-ns{margin-bottom:-1rem}.swagger-ui .nb4-ns{margin-bottom:-2rem}.swagger-ui .nb5-ns{margin-bottom:-4rem}.swagger-ui .nb6-ns{margin-bottom:-8rem}.swagger-ui .nb7-ns{margin-bottom:-16rem}.swagger-ui .nt1-ns{margin-top:-.25rem}.swagger-ui .nt2-ns{margin-top:-.5rem}.swagger-ui .nt3-ns{margin-top:-1rem}.swagger-ui .nt4-ns{margin-top:-2rem}.swagger-ui .nt5-ns{margin-top:-4rem}.swagger-ui .nt6-ns{margin-top:-8rem}.swagger-ui .nt7-ns{margin-top:-16rem}}@media screen and (min-width:30em) and (max-width:60em){.swagger-ui .na1-m{margin:-.25rem}.swagger-ui .na2-m{margin:-.5rem}.swagger-ui .na3-m{margin:-1rem}.swagger-ui .na4-m{margin:-2rem}.swagger-ui .na5-m{margin:-4rem}.swagger-ui .na6-m{margin:-8rem}.swagger-ui .na7-m{margin:-16rem}.swagger-ui .nl1-m{margin-left:-.25rem}.swagger-ui .nl2-m{margin-left:-.5rem}.swagger-ui .nl3-m{margin-left:-1rem}.swagger-ui .nl4-m{margin-left:-2rem}.swagger-ui .nl5-m{margin-left:-4rem}.swagger-ui .nl6-m{margin-left:-8rem}.swagger-ui .nl7-m{margin-left:-16rem}.swagger-ui .nr1-m{margin-right:-.25rem}.swagger-ui .nr2-m{margin-right:-.5rem}.swagger-ui .nr3-m{margin-right:-1rem}.swagger-ui .nr4-m{margin-right:-2rem}.swagger-ui .nr5-m{margin-right:-4rem}.swagger-ui .nr6-m{margin-right:-8rem}.swagger-ui .nr7-m{margin-right:-16rem}.swagger-ui .nb1-m{margin-bottom:-.25rem}.swagger-ui .nb2-m{margin-bottom:-.5rem}.swagger-ui .nb3-m{margin-bottom:-1rem}.swagger-ui .nb4-m{margin-bottom:-2rem}.swagger-ui .nb5-m{margin-bottom:-4rem}.swagger-ui .nb6-m{margin-bottom:-8rem}.swagger-ui .nb7-m{margin-bottom:-16rem}.swagger-ui .nt1-m{margin-top:-.25rem}.swagger-ui .nt2-m{margin-top:-.5rem}.swagger-ui .nt3-m{margin-top:-1rem}.swagger-ui .nt4-m{margin-top:-2rem}.swagger-ui .nt5-m{margin-top:-4rem}.swagger-ui .nt6-m{margin-top:-8rem}.swagger-ui .nt7-m{margin-top:-16rem}}@media screen and (min-width:60em){.swagger-ui .na1-l{margin:-.25rem}.swagger-ui .na2-l{margin:-.5rem}.swagger-ui .na3-l{margin:-1rem}.swagger-ui .na4-l{margin:-2rem}.swagger-ui .na5-l{margin:-4rem}.swagger-ui .na6-l{margin:-8rem}.swagger-ui .na7-l{margin:-16rem}.swagger-ui .nl1-l{margin-left:-.25rem}.swagger-ui .nl2-l{margin-left:-.5rem}.swagger-ui .nl3-l{margin-left:-1rem}.swagger-ui .nl4-l{margin-left:-2rem}.swagger-ui .nl5-l{margin-left:-4rem}.swagger-ui .nl6-l{margin-left:-8rem}.swagger-ui .nl7-l{margin-left:-16rem}.swagger-ui .nr1-l{margin-right:-.25rem}.swagger-ui .nr2-l{margin-right:-.5rem}.swagger-ui .nr3-l{margin-right:-1rem}.swagger-ui .nr4-l{margin-right:-2rem}.swagger-ui .nr5-l{margin-right:-4rem}.swagger-ui .nr6-l{margin-right:-8rem}.swagger-ui .nr7-l{margin-right:-16rem}.swagger-ui .nb1-l{margin-bottom:-.25rem}.swagger-ui .nb2-l{margin-bottom:-.5rem}.swagger-ui .nb3-l{margin-bottom:-1rem}.swagger-ui .nb4-l{margin-bottom:-2rem}.swagger-ui .nb5-l{margin-bottom:-4rem}.swagger-ui .nb6-l{margin-bottom:-8rem}.swagger-ui .nb7-l{margin-bottom:-16rem}.swagger-ui .nt1-l{margin-top:-.25rem}.swagger-ui .nt2-l{margin-top:-.5rem}.swagger-ui .nt3-l{margin-top:-1rem}.swagger-ui .nt4-l{margin-top:-2rem}.swagger-ui .nt5-l{margin-top:-4rem}.swagger-ui .nt6-l{margin-top:-8rem}.swagger-ui .nt7-l{margin-top:-16rem}}.swagger-ui .collapse{border-collapse:collapse;border-spacing:0}.swagger-ui .striped--light-silver:nth-child(odd){background-color:#aaa}.swagger-ui .striped--moon-gray:nth-child(odd){background-color:#ccc}.swagger-ui .striped--light-gray:nth-child(odd){background-color:#eee}.swagger-ui .striped--near-white:nth-child(odd){background-color:#f4f4f4}.swagger-ui .stripe-light:nth-child(odd){background-color:hsla(0,0%,100%,.1)}.swagger-ui .stripe-dark:nth-child(odd){background-color:rgba(0,0,0,.1)}.swagger-ui .strike{text-decoration:line-through}.swagger-ui .underline{text-decoration:underline}.swagger-ui .no-underline{text-decoration:none}@media screen and (min-width:30em){.swagger-ui .strike-ns{text-decoration:line-through}.swagger-ui .underline-ns{text-decoration:underline}.swagger-ui .no-underline-ns{text-decoration:none}}@media screen and (min-width:30em) and (max-width:60em){.swagger-ui .strike-m{text-decoration:line-through}.swagger-ui .underline-m{text-decoration:underline}.swagger-ui .no-underline-m{text-decoration:none}}@media screen and (min-width:60em){.swagger-ui .strike-l{text-decoration:line-through}.swagger-ui .underline-l{text-decoration:underline}.swagger-ui .no-underline-l{text-decoration:none}}.swagger-ui .tl{text-align:left}.swagger-ui .tr{text-align:right}.swagger-ui .tc{text-align:center}.swagger-ui .tj{text-align:justify}@media screen and (min-width:30em){.swagger-ui .tl-ns{text-align:left}.swagger-ui .tr-ns{text-align:right}.swagger-ui .tc-ns{text-align:center}.swagger-ui .tj-ns{text-align:justify}}@media screen and (min-width:30em) and (max-width:60em){.swagger-ui .tl-m{text-align:left}.swagger-ui .tr-m{text-align:right}.swagger-ui .tc-m{text-align:center}.swagger-ui .tj-m{text-align:justify}}@media screen and (min-width:60em){.swagger-ui .tl-l{text-align:left}.swagger-ui .tr-l{text-align:right}.swagger-ui .tc-l{text-align:center}.swagger-ui .tj-l{text-align:justify}}.swagger-ui .ttc{text-transform:capitalize}.swagger-ui .ttl{text-transform:lowercase}.swagger-ui .ttu{text-transform:uppercase}.swagger-ui .ttn{text-transform:none}@media screen and (min-width:30em){.swagger-ui .ttc-ns{text-transform:capitalize}.swagger-ui .ttl-ns{text-transform:lowercase}.swagger-ui .ttu-ns{text-transform:uppercase}.swagger-ui .ttn-ns{text-transform:none}}@media screen and (min-width:30em) and (max-width:60em){.swagger-ui .ttc-m{text-transform:capitalize}.swagger-ui .ttl-m{text-transform:lowercase}.swagger-ui .ttu-m{text-transform:uppercase}.swagger-ui .ttn-m{text-transform:none}}@media screen and (min-width:60em){.swagger-ui .ttc-l{text-transform:capitalize}.swagger-ui .ttl-l{text-transform:lowercase}.swagger-ui .ttu-l{text-transform:uppercase}.swagger-ui .ttn-l{text-transform:none}}.swagger-ui .f-6,.swagger-ui .f-headline{font-size:6rem}.swagger-ui .f-5,.swagger-ui .f-subheadline{font-size:5rem}.swagger-ui .f1{font-size:3rem}.swagger-ui .f2{font-size:2.25rem}.swagger-ui .f3{font-size:1.5rem}.swagger-ui .f4{font-size:1.25rem}.swagger-ui .f5{font-size:1rem}.swagger-ui .f6{font-size:.875rem}.swagger-ui .f7{font-size:.75rem}@media screen and (min-width:30em){.swagger-ui .f-6-ns,.swagger-ui .f-headline-ns{font-size:6rem}.swagger-ui .f-5-ns,.swagger-ui .f-subheadline-ns{font-size:5rem}.swagger-ui .f1-ns{font-size:3rem}.swagger-ui .f2-ns{font-size:2.25rem}.swagger-ui .f3-ns{font-size:1.5rem}.swagger-ui .f4-ns{font-size:1.25rem}.swagger-ui .f5-ns{font-size:1rem}.swagger-ui .f6-ns{font-size:.875rem}.swagger-ui .f7-ns{font-size:.75rem}}@media screen and (min-width:30em) and (max-width:60em){.swagger-ui .f-6-m,.swagger-ui .f-headline-m{font-size:6rem}.swagger-ui .f-5-m,.swagger-ui .f-subheadline-m{font-size:5rem}.swagger-ui .f1-m{font-size:3rem}.swagger-ui .f2-m{font-size:2.25rem}.swagger-ui .f3-m{font-size:1.5rem}.swagger-ui .f4-m{font-size:1.25rem}.swagger-ui .f5-m{font-size:1rem}.swagger-ui .f6-m{font-size:.875rem}.swagger-ui .f7-m{font-size:.75rem}}@media screen and (min-width:60em){.swagger-ui .f-6-l,.swagger-ui .f-headline-l{font-size:6rem}.swagger-ui .f-5-l,.swagger-ui .f-subheadline-l{font-size:5rem}.swagger-ui .f1-l{font-size:3rem}.swagger-ui .f2-l{font-size:2.25rem}.swagger-ui .f3-l{font-size:1.5rem}.swagger-ui .f4-l{font-size:1.25rem}.swagger-ui .f5-l{font-size:1rem}.swagger-ui .f6-l{font-size:.875rem}.swagger-ui .f7-l{font-size:.75rem}}.swagger-ui .measure{max-width:30em}.swagger-ui .measure-wide{max-width:34em}.swagger-ui .measure-narrow{max-width:20em}.swagger-ui .indent{text-indent:1em;margin-top:0;margin-bottom:0}.swagger-ui .small-caps{font-variant:small-caps}.swagger-ui .truncate{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}@media screen and (min-width:30em){.swagger-ui .measure-ns{max-width:30em}.swagger-ui .measure-wide-ns{max-width:34em}.swagger-ui .measure-narrow-ns{max-width:20em}.swagger-ui .indent-ns{text-indent:1em;margin-top:0;margin-bottom:0}.swagger-ui .small-caps-ns{font-variant:small-caps}.swagger-ui .truncate-ns{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}}@media screen and (min-width:30em) and (max-width:60em){.swagger-ui .measure-m{max-width:30em}.swagger-ui .measure-wide-m{max-width:34em}.swagger-ui .measure-narrow-m{max-width:20em}.swagger-ui .indent-m{text-indent:1em;margin-top:0;margin-bottom:0}.swagger-ui .small-caps-m{font-variant:small-caps}.swagger-ui .truncate-m{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}}@media screen and (min-width:60em){.swagger-ui .measure-l{max-width:30em}.swagger-ui .measure-wide-l{max-width:34em}.swagger-ui .measure-narrow-l{max-width:20em}.swagger-ui .indent-l{text-indent:1em;margin-top:0;margin-bottom:0}.swagger-ui .small-caps-l{font-variant:small-caps}.swagger-ui .truncate-l{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}}.swagger-ui .overflow-container{overflow-y:scroll}.swagger-ui .center{margin-right:auto;margin-left:auto}.swagger-ui .mr-auto{margin-right:auto}.swagger-ui .ml-auto{margin-left:auto}@media screen and (min-width:30em){.swagger-ui .center-ns{margin-right:auto;margin-left:auto}.swagger-ui .mr-auto-ns{margin-right:auto}.swagger-ui .ml-auto-ns{margin-left:auto}}@media screen and (min-width:30em) and (max-width:60em){.swagger-ui .center-m{margin-right:auto;margin-left:auto}.swagger-ui .mr-auto-m{margin-right:auto}.swagger-ui .ml-auto-m{margin-left:auto}}@media screen and (min-width:60em){.swagger-ui .center-l{margin-right:auto;margin-left:auto}.swagger-ui .mr-auto-l{margin-right:auto}.swagger-ui .ml-auto-l{margin-left:auto}}.swagger-ui .clip{position:fixed!important;_position:absolute!important;clip:rect(1px 1px 1px 1px);clip:rect(1px,1px,1px,1px)}@media screen and (min-width:30em){.swagger-ui .clip-ns{position:fixed!important;_position:absolute!important;clip:rect(1px 1px 1px 1px);clip:rect(1px,1px,1px,1px)}}@media screen and (min-width:30em) and (max-width:60em){.swagger-ui .clip-m{position:fixed!important;_position:absolute!important;clip:rect(1px 1px 1px 1px);clip:rect(1px,1px,1px,1px)}}@media screen and (min-width:60em){.swagger-ui .clip-l{position:fixed!important;_position:absolute!important;clip:rect(1px 1px 1px 1px);clip:rect(1px,1px,1px,1px)}}.swagger-ui .ws-normal{white-space:normal}.swagger-ui .nowrap{white-space:nowrap}.swagger-ui .pre{white-space:pre}@media screen and (min-width:30em){.swagger-ui .ws-normal-ns{white-space:normal}.swagger-ui .nowrap-ns{white-space:nowrap}.swagger-ui .pre-ns{white-space:pre}}@media screen and (min-width:30em) and (max-width:60em){.swagger-ui .ws-normal-m{white-space:normal}.swagger-ui .nowrap-m{white-space:nowrap}.swagger-ui .pre-m{white-space:pre}}@media screen and (min-width:60em){.swagger-ui .ws-normal-l{white-space:normal}.swagger-ui .nowrap-l{white-space:nowrap}.swagger-ui .pre-l{white-space:pre}}.swagger-ui .v-base{vertical-align:baseline}.swagger-ui .v-mid{vertical-align:middle}.swagger-ui .v-top{vertical-align:top}.swagger-ui .v-btm{vertical-align:bottom}@media screen and (min-width:30em){.swagger-ui .v-base-ns{vertical-align:baseline}.swagger-ui .v-mid-ns{vertical-align:middle}.swagger-ui .v-top-ns{vertical-align:top}.swagger-ui .v-btm-ns{vertical-align:bottom}}@media screen and (min-width:30em) and (max-width:60em){.swagger-ui .v-base-m{vertical-align:baseline}.swagger-ui .v-mid-m{vertical-align:middle}.swagger-ui .v-top-m{vertical-align:top}.swagger-ui .v-btm-m{vertical-align:bottom}}@media screen and (min-width:60em){.swagger-ui .v-base-l{vertical-align:baseline}.swagger-ui .v-mid-l{vertical-align:middle}.swagger-ui .v-top-l{vertical-align:top}.swagger-ui .v-btm-l{vertical-align:bottom}}.swagger-ui .dim{opacity:1;transition:opacity .15s ease-in}.swagger-ui .dim:focus,.swagger-ui .dim:hover{opacity:.5;transition:opacity .15s ease-in}.swagger-ui .dim:active{opacity:.8;transition:opacity .15s ease-out}.swagger-ui .glow{transition:opacity .15s ease-in}.swagger-ui .glow:focus,.swagger-ui .glow:hover{opacity:1;transition:opacity .15s ease-in}.swagger-ui .hide-child .child{opacity:0;transition:opacity .15s ease-in}.swagger-ui .hide-child:active .child,.swagger-ui .hide-child:focus .child,.swagger-ui .hide-child:hover .child{opacity:1;transition:opacity .15s ease-in}.swagger-ui .underline-hover:focus,.swagger-ui .underline-hover:hover{text-decoration:underline}.swagger-ui .grow{-moz-osx-font-smoothing:grayscale;-webkit-backface-visibility:hidden;backface-visibility:hidden;-webkit-transform:translateZ(0);transform:translateZ(0);transition:-webkit-transform .25s ease-out;transition:transform .25s ease-out;transition:transform .25s ease-out, -webkit-transform .25s ease-out}.swagger-ui .grow:focus,.swagger-ui .grow:hover{-webkit-transform:scale(1.05);transform:scale(1.05)}.swagger-ui .grow:active{-webkit-transform:scale(.9);transform:scale(.9)}.swagger-ui .grow-large{-moz-osx-font-smoothing:grayscale;-webkit-backface-visibility:hidden;backface-visibility:hidden;-webkit-transform:translateZ(0);transform:translateZ(0);transition:-webkit-transform .25s ease-in-out;transition:transform .25s ease-in-out;transition:transform .25s ease-in-out, -webkit-transform .25s ease-in-out}.swagger-ui .grow-large:focus,.swagger-ui .grow-large:hover{-webkit-transform:scale(1.2);transform:scale(1.2)}.swagger-ui .grow-large:active{-webkit-transform:scale(.95);transform:scale(.95)}.swagger-ui .pointer:hover{cursor:pointer}.swagger-ui .shadow-hover{cursor:pointer;position:relative;transition:all .5s cubic-bezier(.165,.84,.44,1)}.swagger-ui .shadow-hover:after{content:"";box-shadow:0 0 16px 2px rgba(0,0,0,.2);border-radius:inherit;opacity:0;position:absolute;top:0;left:0;width:100%;height:100%;z-index:-1;transition:opacity .5s cubic-bezier(.165,.84,.44,1)}.swagger-ui .shadow-hover:focus:after,.swagger-ui .shadow-hover:hover:after{opacity:1}.swagger-ui .bg-animate,.swagger-ui .bg-animate:focus,.swagger-ui .bg-animate:hover{transition:background-color .15s ease-in-out}.swagger-ui .z-0{z-index:0}.swagger-ui .z-1{z-index:1}.swagger-ui .z-2{z-index:2}.swagger-ui .z-3{z-index:3}.swagger-ui .z-4{z-index:4}.swagger-ui .z-5{z-index:5}.swagger-ui .z-999{z-index:999}.swagger-ui .z-9999{z-index:9999}.swagger-ui .z-max{z-index:2147483647}.swagger-ui .z-inherit{z-index:inherit}.swagger-ui .z-initial{z-index:auto}.swagger-ui .z-unset{z-index:unset}.swagger-ui .nested-copy-line-height ol,.swagger-ui .nested-copy-line-height p,.swagger-ui .nested-copy-line-height ul{line-height:1.5}.swagger-ui .nested-headline-line-height h1,.swagger-ui .nested-headline-line-height h2,.swagger-ui .nested-headline-line-height h3,.swagger-ui .nested-headline-line-height h4,.swagger-ui .nested-headline-line-height h5,.swagger-ui .nested-headline-line-height h6{line-height:1.25}.swagger-ui .nested-list-reset ol,.swagger-ui .nested-list-reset ul{padding-left:0;margin-left:0;list-style-type:none}.swagger-ui .nested-copy-indent p+p{text-indent:.1em;margin-top:0;margin-bottom:0}.swagger-ui .nested-copy-seperator p+p{margin-top:1.5em}.swagger-ui .nested-img img{width:100%;max-width:100%;display:block}.swagger-ui .nested-links a{color:#357edd;transition:color .15s ease-in}.swagger-ui .nested-links a:focus,.swagger-ui .nested-links a:hover{color:#96ccff;transition:color .15s ease-in}.swagger-ui .wrapper{width:100%;max-width:1460px;margin:0 auto;padding:0 20px;box-sizing:border-box}.swagger-ui .opblock-tag-section{display:flex;flex-direction:column}.swagger-ui .opblock-tag{display:flex;align-items:center;padding:10px 20px 10px 10px;cursor:pointer;transition:all .2s;border-bottom:1px solid rgba(59,65,81,.3)}.swagger-ui .opblock-tag:hover{background:rgba(0,0,0,.02)}.swagger-ui .opblock-tag{font-size:24px;margin:0 0 5px;font-family:sans-serif;color:#3b4151}.swagger-ui .opblock-tag.no-desc span{flex:1}.swagger-ui .opblock-tag svg{transition:all .4s}.swagger-ui .opblock-tag small{font-size:14px;font-weight:400;flex:1;padding:0 10px;font-family:sans-serif;color:#3b4151}.swagger-ui .parameter__type{font-size:12px;padding:5px 0;font-family:monospace;font-weight:600;color:#3b4151}.swagger-ui .parameter-controls{margin-top:.75em}.swagger-ui .examples__title{display:block;font-size:1.1em;font-weight:700;margin-bottom:.75em}.swagger-ui .examples__section{margin-top:1.5em}.swagger-ui .examples__section-header{font-weight:700;font-size:.9rem;margin-bottom:.5rem}.swagger-ui .examples-select{margin-bottom:.75em}.swagger-ui .examples-select__section-label{font-weight:700;font-size:.9rem;margin-right:.5rem}.swagger-ui .example__section{margin-top:1.5em}.swagger-ui .example__section-header{font-weight:700;font-size:.9rem;margin-bottom:.5rem}.swagger-ui .view-line-link{position:relative;top:3px;width:20px;margin:0 5px;cursor:pointer;transition:all .5s}.swagger-ui .opblock{margin:0 0 15px;border:1px solid #000;border-radius:4px;box-shadow:0 0 3px rgba(0,0,0,.19)}.swagger-ui .opblock .tab-header{display:flex;flex:1}.swagger-ui .opblock .tab-header .tab-item{padding:0 40px;cursor:pointer}.swagger-ui .opblock .tab-header .tab-item:first-of-type{padding:0 40px 0 0}.swagger-ui .opblock .tab-header .tab-item.active h4 span{position:relative}.swagger-ui .opblock .tab-header .tab-item.active h4 span:after{position:absolute;bottom:-15px;left:50%;width:120%;height:4px;content:"";-webkit-transform:translateX(-50%);transform:translateX(-50%);background:grey}.swagger-ui .opblock.is-open .opblock-summary{border-bottom:1px solid #000}.swagger-ui .opblock .opblock-section-header{display:flex;align-items:center;padding:8px 20px;min-height:50px;background:hsla(0,0%,100%,.8);box-shadow:0 1px 2px rgba(0,0,0,.1)}.swagger-ui .opblock .opblock-section-header>label{font-size:12px;font-weight:700;display:flex;align-items:center;margin:0 0 0 auto;font-family:sans-serif;color:#3b4151}.swagger-ui .opblock .opblock-section-header>label>span{padding:0 10px 0 0}.swagger-ui .opblock .opblock-section-header h4{font-size:14px;flex:1;margin:0;font-family:sans-serif;color:#3b4151}.swagger-ui .opblock .opblock-summary-method{font-size:14px;font-weight:700;min-width:80px;padding:6px 15px;text-align:center;border-radius:3px;background:#000;text-shadow:0 1px 0 rgba(0,0,0,.1);font-family:sans-serif;color:#fff}.swagger-ui .opblock .opblock-summary-operation-id,.swagger-ui .opblock .opblock-summary-path,.swagger-ui .opblock .opblock-summary-path__deprecated{font-size:16px;display:flex;align-items:center;word-break:break-word;padding:0 10px;font-family:monospace;font-weight:600;color:#3b4151}@media (max-width:768px){.swagger-ui .opblock .opblock-summary-operation-id,.swagger-ui .opblock .opblock-summary-path,.swagger-ui .opblock .opblock-summary-path__deprecated{font-size:12px}}.swagger-ui .opblock .opblock-summary-path__deprecated{text-decoration:line-through}.swagger-ui .opblock .opblock-summary-operation-id{font-size:14px}.swagger-ui .opblock .opblock-summary-description{font-size:13px;flex:1 1 auto;word-break:break-word;font-family:sans-serif;color:#3b4151}.swagger-ui .opblock .opblock-summary{display:flex;align-items:center;padding:5px;cursor:pointer}.swagger-ui .opblock .opblock-summary .view-line-link{position:relative;top:2px;width:0;margin:0;cursor:pointer;transition:all .5s}.swagger-ui .opblock .opblock-summary:hover .view-line-link{width:18px;margin:0 5px}.swagger-ui .opblock.opblock-post{border-color:#49cc90;background:rgba(73,204,144,.1)}.swagger-ui .opblock.opblock-post .opblock-summary-method{background:#49cc90}.swagger-ui .opblock.opblock-post .opblock-summary{border-color:#49cc90}.swagger-ui .opblock.opblock-post .tab-header .tab-item.active h4 span:after{background:#49cc90}.swagger-ui .opblock.opblock-put{border-color:#fca130;background:rgba(252,161,48,.1)}.swagger-ui .opblock.opblock-put .opblock-summary-method{background:#fca130}.swagger-ui .opblock.opblock-put .opblock-summary{border-color:#fca130}.swagger-ui .opblock.opblock-put .tab-header .tab-item.active h4 span:after{background:#fca130}.swagger-ui .opblock.opblock-delete{border-color:#f93e3e;background:rgba(249,62,62,.1)}.swagger-ui .opblock.opblock-delete .opblock-summary-method{background:#f93e3e}.swagger-ui .opblock.opblock-delete .opblock-summary{border-color:#f93e3e}.swagger-ui .opblock.opblock-delete .tab-header .tab-item.active h4 span:after{background:#f93e3e}.swagger-ui .opblock.opblock-get{border-color:#61affe;background:rgba(97,175,254,.1)}.swagger-ui .opblock.opblock-get .opblock-summary-method{background:#61affe}.swagger-ui .opblock.opblock-get .opblock-summary{border-color:#61affe}.swagger-ui .opblock.opblock-get .tab-header .tab-item.active h4 span:after{background:#61affe}.swagger-ui .opblock.opblock-patch{border-color:#50e3c2;background:rgba(80,227,194,.1)}.swagger-ui .opblock.opblock-patch .opblock-summary-method{background:#50e3c2}.swagger-ui .opblock.opblock-patch .opblock-summary{border-color:#50e3c2}.swagger-ui .opblock.opblock-patch .tab-header .tab-item.active h4 span:after{background:#50e3c2}.swagger-ui .opblock.opblock-head{border-color:#9012fe;background:rgba(144,18,254,.1)}.swagger-ui .opblock.opblock-head .opblock-summary-method{background:#9012fe}.swagger-ui .opblock.opblock-head .opblock-summary{border-color:#9012fe}.swagger-ui .opblock.opblock-head .tab-header .tab-item.active h4 span:after{background:#9012fe}.swagger-ui .opblock.opblock-options{border-color:#0d5aa7;background:rgba(13,90,167,.1)}.swagger-ui .opblock.opblock-options .opblock-summary-method{background:#0d5aa7}.swagger-ui .opblock.opblock-options .opblock-summary{border-color:#0d5aa7}.swagger-ui .opblock.opblock-options .tab-header .tab-item.active h4 span:after{background:#0d5aa7}.swagger-ui .opblock.opblock-deprecated{opacity:.6;border-color:#ebebeb;background:hsla(0,0%,92.2%,.1)}.swagger-ui .opblock.opblock-deprecated .opblock-summary-method{background:#ebebeb}.swagger-ui .opblock.opblock-deprecated .opblock-summary{border-color:#ebebeb}.swagger-ui .opblock.opblock-deprecated .tab-header .tab-item.active h4 span:after{background:#ebebeb}.swagger-ui .opblock .opblock-schemes{padding:8px 20px}.swagger-ui .opblock .opblock-schemes .schemes-title{padding:0 10px 0 0}.swagger-ui .filter .operation-filter-input{width:100%;margin:20px 0;padding:10px;border:2px solid #d8dde7}.swagger-ui .model-example{margin-top:1em}.swagger-ui .tab{display:flex;padding:0;list-style:none}.swagger-ui .tab li{font-size:12px;min-width:60px;padding:0;cursor:pointer;font-family:sans-serif;color:#3b4151}.swagger-ui .tab li:first-of-type{position:relative;padding-left:0;padding-right:12px}.swagger-ui .tab li:first-of-type:after{position:absolute;top:0;right:6px;width:1px;height:100%;content:"";background:rgba(0,0,0,.2)}.swagger-ui .tab li.active{font-weight:700}.swagger-ui .opblock-description-wrapper,.swagger-ui .opblock-external-docs-wrapper,.swagger-ui .opblock-title_normal{font-size:12px;margin:0 0 5px;padding:15px 20px;font-family:sans-serif;color:#3b4151}.swagger-ui .opblock-description-wrapper h4,.swagger-ui .opblock-external-docs-wrapper h4,.swagger-ui .opblock-title_normal h4{font-size:12px;margin:0 0 5px;font-family:sans-serif;color:#3b4151}.swagger-ui .opblock-description-wrapper p,.swagger-ui .opblock-external-docs-wrapper p,.swagger-ui .opblock-title_normal p{font-size:14px;margin:0;font-family:sans-serif;color:#3b4151}.swagger-ui .opblock-external-docs-wrapper h4{padding-left:0}.swagger-ui .execute-wrapper{padding:20px;text-align:right}.swagger-ui .execute-wrapper .btn{width:100%;padding:8px 40px}.swagger-ui .body-param-options{display:flex;flex-direction:column}.swagger-ui .body-param-options .body-param-edit{padding:10px 0}.swagger-ui .body-param-options label{padding:8px 0}.swagger-ui .body-param-options label select{margin:3px 0 0}.swagger-ui .responses-inner{padding:20px}.swagger-ui .responses-inner h4,.swagger-ui .responses-inner h5{font-size:12px;margin:10px 0 5px;font-family:sans-serif;color:#3b4151}.swagger-ui .response-col_status{font-size:14px;font-family:sans-serif;color:#3b4151}.swagger-ui .response-col_status .response-undocumented{font-size:11px;font-family:monospace;font-weight:600;color:#909090}.swagger-ui .response-col_links{padding-left:2em;max-width:40em;font-size:14px;font-family:sans-serif;color:#3b4151}.swagger-ui .response-col_links .response-undocumented{font-size:11px;font-family:monospace;font-weight:600;color:#909090}.swagger-ui .opblock-body .opblock-loading-animation{display:block;margin:3em auto}.swagger-ui .opblock-body pre.microlight{font-size:12px;margin:0;padding:10px;white-space:pre-wrap;word-wrap:break-word;word-break:break-all;word-break:break-word;-webkit-hyphens:auto;-ms-hyphens:auto;hyphens:auto;border-radius:4px;background:#41444e;overflow-wrap:break-word;font-family:monospace;font-weight:600;color:#fff}.swagger-ui .opblock-body pre.microlight span{color:#fff!important}.swagger-ui .opblock-body pre.microlight .headerline{display:block}.swagger-ui .highlight-code{position:relative}.swagger-ui .highlight-code>.microlight{overflow-y:auto;max-height:400px;min-height:6em}.swagger-ui .download-contents{position:absolute;bottom:10px;right:10px;cursor:pointer;background:#7d8293;text-align:center;padding:5px;border-radius:4px;font-family:sans-serif;font-weight:600;color:#fff;font-size:14px;height:30px;width:75px}.swagger-ui .scheme-container{margin:0 0 20px;padding:30px 0;background:#fff;box-shadow:0 1px 2px 0 rgba(0,0,0,.15)}.swagger-ui .scheme-container .schemes{display:flex;align-items:flex-end}.swagger-ui .scheme-container .schemes>label{font-size:12px;font-weight:700;display:flex;flex-direction:column;margin:-20px 15px 0 0;font-family:sans-serif;color:#3b4151}.swagger-ui .scheme-container .schemes>label select{min-width:130px;text-transform:uppercase}.swagger-ui .loading-container{padding:40px 0 60px;margin-top:1em;min-height:1px;display:flex;justify-content:center;align-items:center;flex-direction:column}.swagger-ui .loading-container .loading{position:relative}.swagger-ui .loading-container .loading:after{font-size:10px;font-weight:700;position:absolute;top:50%;left:50%;content:"loading";-webkit-transform:translate(-50%,-50%);transform:translate(-50%,-50%);text-transform:uppercase;font-family:sans-serif;color:#3b4151}.swagger-ui .loading-container .loading:before{position:absolute;top:50%;left:50%;display:block;width:60px;height:60px;margin:-30px;content:"";-webkit-animation:rotation 1s linear infinite,opacity .5s;animation:rotation 1s linear infinite,opacity .5s;opacity:1;border:2px solid rgba(85,85,85,.1);border-top-color:rgba(0,0,0,.6);border-radius:100%;-webkit-backface-visibility:hidden;backface-visibility:hidden}@-webkit-keyframes rotation{to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}@keyframes rotation{to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}.swagger-ui .response-controls{padding-top:1em;display:flex}.swagger-ui .response-control-media-type{margin-right:1em}.swagger-ui .response-control-media-type--accept-controller select{border-color:green}.swagger-ui .response-control-media-type__accept-message{color:green;font-size:.7em}.swagger-ui .response-control-examples__title,.swagger-ui .response-control-media-type__title{display:block;margin-bottom:.2em;font-size:.7em}@-webkit-keyframes blinker{50%{opacity:0}}@keyframes blinker{50%{opacity:0}}.swagger-ui section h3{font-family:sans-serif;color:#3b4151}.swagger-ui a.nostyle{display:inline}.swagger-ui a.nostyle,.swagger-ui a.nostyle:visited{text-decoration:inherit;color:inherit;cursor:pointer}.swagger-ui .version-pragma{height:100%;padding:5em 0}.swagger-ui .version-pragma__message{display:flex;justify-content:center;height:100%;font-size:1.2em;text-align:center;line-height:1.5em;padding:0 .6em}.swagger-ui .version-pragma__message>div{max-width:55ch;flex:1}.swagger-ui .version-pragma__message code{background-color:#dedede;padding:4px 4px 2px;white-space:pre}.swagger-ui .btn{font-size:14px;font-weight:700;padding:5px 23px;transition:all .3s;border:2px solid grey;border-radius:4px;background:transparent;box-shadow:0 1px 2px rgba(0,0,0,.1);font-family:sans-serif;color:#3b4151}.swagger-ui .btn.btn-sm{font-size:12px;padding:4px 23px}.swagger-ui .btn[disabled]{cursor:not-allowed;opacity:.3}.swagger-ui .btn:hover{box-shadow:0 0 5px rgba(0,0,0,.3)}.swagger-ui .btn.cancel{border-color:#ff6060;background-color:transparent;font-family:sans-serif;color:#ff6060}.swagger-ui .btn.authorize{line-height:1;display:inline;color:#49cc90;border-color:#49cc90;background-color:transparent}.swagger-ui .btn.authorize span{float:left;padding:4px 20px 0 0}.swagger-ui .btn.authorize svg{fill:#49cc90}.swagger-ui .btn.execute{background-color:#4990e2;color:#fff;border-color:#4990e2}.swagger-ui .btn-group{display:flex;padding:30px}.swagger-ui .btn-group .btn{flex:1}.swagger-ui .btn-group .btn:first-child{border-radius:4px 0 0 4px}.swagger-ui .btn-group .btn:last-child{border-radius:0 4px 4px 0}.swagger-ui .authorization__btn{padding:0 10px;border:none;background:none}.swagger-ui .authorization__btn.locked{opacity:1}.swagger-ui .authorization__btn.unlocked{opacity:.4}.swagger-ui .expand-methods,.swagger-ui .expand-operation{border:none;background:none}.swagger-ui .expand-methods svg,.swagger-ui .expand-operation svg{width:20px;height:20px}.swagger-ui .expand-methods{padding:0 10px}.swagger-ui .expand-methods:hover svg{fill:#404040}.swagger-ui .expand-methods svg{transition:all .3s;fill:#707070}.swagger-ui button{cursor:pointer;outline:none}.swagger-ui button.invalid{-webkit-animation:shake .4s 1;animation:shake .4s 1;border-color:#f93e3e;background:#feebeb}.swagger-ui select{font-size:14px;font-weight:700;padding:5px 40px 5px 10px;border:2px solid #41444e;border-radius:4px;background:#f7f7f7 url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyMCAyMCI+PHBhdGggZD0iTTEzLjQxOCA3Ljg1OWEuNjk1LjY5NSAwIDAxLjk3OCAwIC42OC42OCAwIDAxMCAuOTY5bC0zLjkwOCAzLjgzYS42OTcuNjk3IDAgMDEtLjk3OSAwbC0zLjkwOC0zLjgzYS42OC42OCAwIDAxMC0uOTY5LjY5NS42OTUgMCAwMS45NzggMEwxMCAxMWwzLjQxOC0zLjE0MXoiLz48L3N2Zz4=) right 10px center no-repeat;background-size:20px;box-shadow:0 1px 2px 0 rgba(0,0,0,.25);font-family:sans-serif;color:#3b4151;-webkit-appearance:none;-moz-appearance:none;appearance:none}.swagger-ui select[multiple]{margin:5px 0;padding:5px;background:#f7f7f7}.swagger-ui select.invalid{-webkit-animation:shake .4s 1;animation:shake .4s 1;border-color:#f93e3e;background:#feebeb}.swagger-ui .opblock-body select{min-width:230px}@media (max-width:768px){.swagger-ui .opblock-body select{min-width:180px}}.swagger-ui label{font-size:12px;font-weight:700;margin:0 0 5px;font-family:sans-serif;color:#3b4151}.swagger-ui input[type=email],.swagger-ui input[type=file],.swagger-ui input[type=password],.swagger-ui input[type=search],.swagger-ui input[type=text],.swagger-ui textarea{min-width:100px;margin:5px 0;padding:8px 10px;border:1px solid #d9d9d9;border-radius:4px;background:#fff}@media (max-width:768px){.swagger-ui input[type=email],.swagger-ui input[type=file],.swagger-ui input[type=password],.swagger-ui input[type=search],.swagger-ui input[type=text],.swagger-ui textarea{max-width:175px}}.swagger-ui input[type=email].invalid,.swagger-ui input[type=file].invalid,.swagger-ui input[type=password].invalid,.swagger-ui input[type=search].invalid,.swagger-ui input[type=text].invalid,.swagger-ui textarea.invalid{-webkit-animation:shake .4s 1;animation:shake .4s 1;border-color:#f93e3e;background:#feebeb}.swagger-ui input[disabled],.swagger-ui select[disabled],.swagger-ui textarea[disabled]{background-color:#fafafa;color:#888;cursor:not-allowed}.swagger-ui select[disabled]{border-color:#888}.swagger-ui textarea[disabled]{background-color:#41444e;color:#fff}@-webkit-keyframes shake{10%,90%{-webkit-transform:translate3d(-1px,0,0);transform:translate3d(-1px,0,0)}20%,80%{-webkit-transform:translate3d(2px,0,0);transform:translate3d(2px,0,0)}30%,50%,70%{-webkit-transform:translate3d(-4px,0,0);transform:translate3d(-4px,0,0)}40%,60%{-webkit-transform:translate3d(4px,0,0);transform:translate3d(4px,0,0)}}@keyframes shake{10%,90%{-webkit-transform:translate3d(-1px,0,0);transform:translate3d(-1px,0,0)}20%,80%{-webkit-transform:translate3d(2px,0,0);transform:translate3d(2px,0,0)}30%,50%,70%{-webkit-transform:translate3d(-4px,0,0);transform:translate3d(-4px,0,0)}40%,60%{-webkit-transform:translate3d(4px,0,0);transform:translate3d(4px,0,0)}}.swagger-ui textarea{font-size:12px;width:100%;min-height:280px;padding:10px;border:none;border-radius:4px;outline:none;background:hsla(0,0%,100%,.8);font-family:monospace;font-weight:600;color:#3b4151}.swagger-ui textarea:focus{border:2px solid #61affe}.swagger-ui textarea.curl{font-size:12px;min-height:100px;margin:0;padding:10px;resize:none;border-radius:4px;background:#41444e;font-family:monospace;font-weight:600;color:#fff}.swagger-ui .checkbox{padding:5px 0 10px;transition:opacity .5s;color:#303030}.swagger-ui .checkbox label{display:flex}.swagger-ui .checkbox p{font-weight:400!important;font-style:italic;margin:0!important;font-family:monospace;font-weight:600;color:#3b4151}.swagger-ui .checkbox input[type=checkbox]{display:none}.swagger-ui .checkbox input[type=checkbox]+label>.item{position:relative;top:3px;display:inline-block;width:16px;height:16px;margin:0 8px 0 0;padding:5px;cursor:pointer;border-radius:1px;background:#e8e8e8;box-shadow:0 0 0 2px #e8e8e8;flex:none}.swagger-ui .checkbox input[type=checkbox]+label>.item:active{-webkit-transform:scale(.9);transform:scale(.9)}.swagger-ui .checkbox input[type=checkbox]:checked+label>.item{background:#e8e8e8 url("data:image/svg+xml;charset=utf-8,%3Csvg width='10' height='8' viewBox='3 7 10 8' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill='%2341474E' fill-rule='evenodd' d='M6.333 15L3 11.667l1.333-1.334 2 2L11.667 7 13 8.333z'/%3E%3C/svg%3E") 50% no-repeat}.swagger-ui .dialog-ux{position:fixed;z-index:9999;top:0;right:0;bottom:0;left:0}.swagger-ui .dialog-ux .backdrop-ux{position:fixed;top:0;right:0;bottom:0;left:0;background:rgba(0,0,0,.8)}.swagger-ui .dialog-ux .modal-ux{position:absolute;z-index:9999;top:50%;left:50%;width:100%;min-width:300px;max-width:650px;-webkit-transform:translate(-50%,-50%);transform:translate(-50%,-50%);border:1px solid #ebebeb;border-radius:4px;background:#fff;box-shadow:0 10px 30px 0 rgba(0,0,0,.2)}.swagger-ui .dialog-ux .modal-ux-content{overflow-y:auto;max-height:540px;padding:20px}.swagger-ui .dialog-ux .modal-ux-content p{font-size:12px;margin:0 0 5px;color:#41444e;font-family:sans-serif;color:#3b4151}.swagger-ui .dialog-ux .modal-ux-content h4{font-size:18px;font-weight:600;margin:15px 0 0;font-family:sans-serif;color:#3b4151}.swagger-ui .dialog-ux .modal-ux-header{display:flex;padding:12px 0;border-bottom:1px solid #ebebeb;align-items:center}.swagger-ui .dialog-ux .modal-ux-header .close-modal{padding:0 10px;border:none;background:none;-webkit-appearance:none;-moz-appearance:none;appearance:none}.swagger-ui .dialog-ux .modal-ux-header h3{font-size:20px;font-weight:600;margin:0;padding:0 20px;flex:1;font-family:sans-serif;color:#3b4151}.swagger-ui .model{font-size:12px;font-weight:300;font-family:monospace;font-weight:600;color:#3b4151}.swagger-ui .model .deprecated span,.swagger-ui .model .deprecated td{color:#a0a0a0!important}.swagger-ui .model .deprecated>td:first-of-type{text-decoration:line-through}.swagger-ui .model-toggle{font-size:10px;position:relative;top:6px;display:inline-block;margin:auto .3em;cursor:pointer;transition:-webkit-transform .15s ease-in;transition:transform .15s ease-in;transition:transform .15s ease-in, -webkit-transform .15s ease-in;-webkit-transform:rotate(90deg);transform:rotate(90deg);-webkit-transform-origin:50% 50%;transform-origin:50% 50%}.swagger-ui .model-toggle.collapsed{-webkit-transform:rotate(0deg);transform:rotate(0deg)}.swagger-ui .model-toggle:after{display:block;width:20px;height:20px;content:"";background:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24'%3E%3Cpath d='M10 6L8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z'/%3E%3C/svg%3E") 50% no-repeat;background-size:100%}.swagger-ui .model-jump-to-path{position:relative;cursor:pointer}.swagger-ui .model-jump-to-path .view-line-link{position:absolute;top:-.4em;cursor:pointer}.swagger-ui .model-title{position:relative}.swagger-ui .model-title:hover .model-hint{visibility:visible}.swagger-ui .model-hint{position:absolute;top:-1.8em;visibility:hidden;padding:.1em .5em;white-space:nowrap;color:#ebebeb;border-radius:4px;background:rgba(0,0,0,.7)}.swagger-ui .model p{margin:0 0 1em}.swagger-ui section.models{margin:30px 0;border:1px solid rgba(59,65,81,.3);border-radius:4px}.swagger-ui section.models.is-open{padding:0 0 20px}.swagger-ui section.models.is-open h4{margin:0 0 5px;border-bottom:1px solid rgba(59,65,81,.3)}.swagger-ui section.models h4{font-size:16px;display:flex;align-items:center;margin:0;padding:10px 20px 10px 10px;cursor:pointer;transition:all .2s;font-family:sans-serif;color:#606060}.swagger-ui section.models h4 svg{transition:all .4s}.swagger-ui section.models h4 span{flex:1}.swagger-ui section.models h4:hover{background:rgba(0,0,0,.02)}.swagger-ui section.models h5{font-size:16px;margin:0 0 10px;font-family:sans-serif;color:#707070}.swagger-ui section.models .model-jump-to-path{position:relative;top:5px}.swagger-ui section.models .model-container{margin:0 20px 15px;position:relative;transition:all .5s;border-radius:4px;background:rgba(0,0,0,.05)}.swagger-ui section.models .model-container:hover{background:rgba(0,0,0,.07)}.swagger-ui section.models .model-container:first-of-type{margin:20px}.swagger-ui section.models .model-container:last-of-type{margin:0 20px}.swagger-ui section.models .model-container .models-jump-to-path{position:absolute;top:8px;right:5px;opacity:.65}.swagger-ui section.models .model-box{background:none}.swagger-ui .model-box{padding:10px;display:inline-block;border-radius:4px;background:rgba(0,0,0,.1)}.swagger-ui .model-box .model-jump-to-path{position:relative;top:4px}.swagger-ui .model-box.deprecated{opacity:.5}.swagger-ui .model-title{font-size:16px;font-family:sans-serif;color:#505050}.swagger-ui .model-deprecated-warning{font-size:16px;font-weight:600;margin-right:1em;font-family:sans-serif;color:#f93e3e}.swagger-ui span>span.model .brace-close{padding:0 0 0 10px}.swagger-ui .prop-name{display:inline-block;margin-right:1em}.swagger-ui .prop-type{color:#55a}.swagger-ui .prop-enum{display:block}.swagger-ui .prop-format{color:#606060}.swagger-ui .servers>label{font-size:12px;margin:-20px 15px 0 0;font-family:sans-serif;color:#3b4151}.swagger-ui .servers>label select{min-width:130px;max-width:100%}.swagger-ui .servers h4.message{padding-bottom:2em}.swagger-ui .servers table tr{width:30em}.swagger-ui .servers table td{display:inline-block;max-width:15em;vertical-align:middle;padding-top:10px;padding-bottom:10px}.swagger-ui .servers table td:first-of-type{padding-right:2em}.swagger-ui .servers table td input{width:100%;height:100%}.swagger-ui .servers .computed-url{margin:2em 0}.swagger-ui .servers .computed-url code{display:inline-block;padding:4px;font-size:16px;margin:0 1em}.swagger-ui .servers-title{font-size:12px;font-weight:700}.swagger-ui .operation-servers h4.message{margin-bottom:2em}.swagger-ui table{width:100%;padding:0 10px;border-collapse:collapse}.swagger-ui table.model tbody tr td{padding:0;vertical-align:top}.swagger-ui table.model tbody tr td:first-of-type{width:174px;padding:0 0 0 2em}.swagger-ui table.headers td{font-size:12px;font-weight:300;vertical-align:middle;font-family:monospace;font-weight:600;color:#3b4151}.swagger-ui table tbody tr td{padding:10px 0 0;vertical-align:top}.swagger-ui table tbody tr td:first-of-type{max-width:20%;min-width:6em;padding:10px 0}.swagger-ui table thead tr td,.swagger-ui table thead tr th{font-size:12px;font-weight:700;padding:12px 0;text-align:left;border-bottom:1px solid rgba(59,65,81,.2);font-family:sans-serif;color:#3b4151}.swagger-ui .parameters-col_description{width:99%;margin-bottom:2em}.swagger-ui .parameters-col_description input[type=text]{width:100%;max-width:340px}.swagger-ui .parameters-col_description select{border-width:1px}.swagger-ui .parameter__name{font-size:16px;font-weight:400;margin-right:.75em;font-family:sans-serif;color:#3b4151}.swagger-ui .parameter__name.required{font-weight:700}.swagger-ui .parameter__name.required:after{font-size:10px;position:relative;top:-6px;padding:5px;content:"required";color:rgba(255,0,0,.6)}.swagger-ui .parameter__extension,.swagger-ui .parameter__in{font-size:12px;font-style:italic;font-family:monospace;font-weight:600;color:grey}.swagger-ui .parameter__deprecated{font-size:12px;font-style:italic;font-family:monospace;font-weight:600;color:red}.swagger-ui .parameter__empty_value_toggle{font-size:13px;padding-top:5px;padding-bottom:12px}.swagger-ui .parameter__empty_value_toggle input{margin-right:7px}.swagger-ui .parameter__empty_value_toggle.disabled{opacity:.7}.swagger-ui .table-container{padding:20px}.swagger-ui .response-col_description{width:99%}.swagger-ui .response-col_links{min-width:6em}.swagger-ui .topbar{padding:10px 0;background-color:#1b1b1b}.swagger-ui .topbar .topbar-wrapper,.swagger-ui .topbar a{display:flex;align-items:center}.swagger-ui .topbar a{font-size:1.5em;font-weight:700;flex:1;max-width:300px;text-decoration:none;font-family:sans-serif;color:#fff}.swagger-ui .topbar a span{margin:0;padding:0 10px}.swagger-ui .topbar .download-url-wrapper{display:flex;flex:3;justify-content:flex-end}.swagger-ui .topbar .download-url-wrapper input[type=text]{width:100%;margin:0;border:2px solid #62a03f;border-radius:4px 0 0 4px;outline:none}.swagger-ui .topbar .download-url-wrapper .select-label{display:flex;align-items:center;width:100%;max-width:600px;margin:0;color:#f0f0f0}.swagger-ui .topbar .download-url-wrapper .select-label span{font-size:16px;flex:1;padding:0 10px 0 0;text-align:right}.swagger-ui .topbar .download-url-wrapper .select-label select{flex:2;width:100%;border:2px solid #62a03f;outline:none;box-shadow:none}.swagger-ui .topbar .download-url-wrapper .download-url-button{font-size:16px;font-weight:700;padding:4px 30px;border:none;border-radius:0 4px 4px 0;background:#62a03f;font-family:sans-serif;color:#fff}.swagger-ui .info{margin:50px 0}.swagger-ui .info hgroup.main{margin:0 0 20px}.swagger-ui .info hgroup.main a{font-size:12px}.swagger-ui .info pre{font-size:14px}.swagger-ui .info li,.swagger-ui .info p,.swagger-ui .info table{font-size:14px;font-family:sans-serif;color:#3b4151}.swagger-ui .info h1,.swagger-ui .info h2,.swagger-ui .info h3,.swagger-ui .info h4,.swagger-ui .info h5{font-family:sans-serif;color:#3b4151}.swagger-ui .info a{font-size:14px;transition:all .4s;font-family:sans-serif;color:#4990e2}.swagger-ui .info a:hover{color:#1f69c0}.swagger-ui .info>div{margin:0 0 5px}.swagger-ui .info .base-url{font-size:12px;font-weight:300!important;margin:0;font-family:monospace;font-weight:600;color:#3b4151}.swagger-ui .info .title{font-size:36px;margin:0;font-family:sans-serif;color:#3b4151}.swagger-ui .info .title small{font-size:10px;position:relative;top:-5px;display:inline-block;margin:0 0 0 5px;padding:2px 4px;vertical-align:super;border-radius:57px;background:#7d8492}.swagger-ui .info .title small pre{margin:0;padding:0;font-family:sans-serif;color:#fff}.swagger-ui .auth-btn-wrapper{display:flex;padding:10px 0;justify-content:center}.swagger-ui .auth-btn-wrapper .btn-done{margin-right:1em}.swagger-ui .auth-wrapper{display:flex;flex:1;justify-content:flex-end}.swagger-ui .auth-wrapper .authorize{padding-right:20px;margin-right:10px}.swagger-ui .auth-container{margin:0 0 10px;padding:10px 20px;border-bottom:1px solid #ebebeb}.swagger-ui .auth-container:last-of-type{margin:0;padding:10px 20px;border:0}.swagger-ui .auth-container h4{margin:5px 0 15px!important}.swagger-ui .auth-container .wrapper{margin:0;padding:0}.swagger-ui .auth-container input[type=password],.swagger-ui .auth-container input[type=text]{min-width:230px}.swagger-ui .auth-container .errors{font-size:12px;padding:10px;border-radius:4px;font-family:monospace;font-weight:600;color:#3b4151}.swagger-ui .scopes h2{font-size:14px;font-family:sans-serif;color:#3b4151}.swagger-ui .scope-def{padding:0 0 20px}.swagger-ui .errors-wrapper{margin:20px;padding:10px 20px;-webkit-animation:scaleUp .5s;animation:scaleUp .5s;border:2px solid #f93e3e;border-radius:4px;background:rgba(249,62,62,.1)}.swagger-ui .errors-wrapper .error-wrapper{margin:0 0 10px}.swagger-ui .errors-wrapper .errors h4{font-size:14px;margin:0;font-family:monospace;font-weight:600;color:#3b4151}.swagger-ui .errors-wrapper .errors small{color:#606060}.swagger-ui .errors-wrapper hgroup{display:flex;align-items:center}.swagger-ui .errors-wrapper hgroup h4{font-size:20px;margin:0;flex:1;font-family:sans-serif;color:#3b4151}@-webkit-keyframes scaleUp{0%{-webkit-transform:scale(.8);transform:scale(.8);opacity:0}to{-webkit-transform:scale(1);transform:scale(1);opacity:1}}@keyframes scaleUp{0%{-webkit-transform:scale(.8);transform:scale(.8);opacity:0}to{-webkit-transform:scale(1);transform:scale(1);opacity:1}}.swagger-ui .Resizer.vertical.disabled{display:none}.swagger-ui .markdown p,.swagger-ui .markdown pre,.swagger-ui .renderedMarkdown p,.swagger-ui .renderedMarkdown pre{margin:1em auto}.swagger-ui .markdown pre,.swagger-ui .renderedMarkdown pre{color:#000;font-weight:400;white-space:pre-wrap;background:none;padding:0}.swagger-ui .markdown code,.swagger-ui .renderedMarkdown code{font-size:14px;padding:5px 7px;border-radius:4px;background:rgba(0,0,0,.05);font-family:monospace;font-weight:600;color:#9012fe}.swagger-ui .markdown pre>code,.swagger-ui .renderedMarkdown pre>code{display:block} + +/*# sourceMappingURL=swagger-ui.css.map*/ \ No newline at end of file diff --git a/docs/typescript/favicons/android-144x144.png b/docs/typescript/favicons/android-144x144.png new file mode 100755 index 0000000..8851c09 Binary files /dev/null and b/docs/typescript/favicons/android-144x144.png differ diff --git a/docs/typescript/favicons/android-192x192.png b/docs/typescript/favicons/android-192x192.png new file mode 100755 index 0000000..94b2ad2 Binary files /dev/null and b/docs/typescript/favicons/android-192x192.png differ diff --git a/docs/typescript/favicons/android-36x36.png b/docs/typescript/favicons/android-36x36.png new file mode 100755 index 0000000..7ec5cf6 Binary files /dev/null and b/docs/typescript/favicons/android-36x36.png differ diff --git a/docs/typescript/favicons/android-48x48.png b/docs/typescript/favicons/android-48x48.png new file mode 100755 index 0000000..419a445 Binary files /dev/null and b/docs/typescript/favicons/android-48x48.png differ diff --git a/docs/typescript/favicons/android-72x72.png b/docs/typescript/favicons/android-72x72.png new file mode 100755 index 0000000..230b18f Binary files /dev/null and b/docs/typescript/favicons/android-72x72.png differ diff --git a/docs/typescript/favicons/android-96x96.png b/docs/typescript/favicons/android-96x96.png new file mode 100755 index 0000000..8cc6989 Binary files /dev/null and b/docs/typescript/favicons/android-96x96.png differ diff --git a/docs/typescript/favicons/apple-touch-icon-180x180.png b/docs/typescript/favicons/apple-touch-icon-180x180.png new file mode 100755 index 0000000..03d0b51 Binary files /dev/null and b/docs/typescript/favicons/apple-touch-icon-180x180.png differ diff --git a/docs/typescript/favicons/favicon-1024.png b/docs/typescript/favicons/favicon-1024.png new file mode 100644 index 0000000..920f107 Binary files /dev/null and b/docs/typescript/favicons/favicon-1024.png differ diff --git a/docs/typescript/favicons/favicon-16x16.png b/docs/typescript/favicons/favicon-16x16.png new file mode 100755 index 0000000..ce918ee Binary files /dev/null and b/docs/typescript/favicons/favicon-16x16.png differ diff --git a/docs/typescript/favicons/favicon-256.png b/docs/typescript/favicons/favicon-256.png new file mode 100644 index 0000000..ebd3f8c Binary files /dev/null and b/docs/typescript/favicons/favicon-256.png differ diff --git a/docs/typescript/favicons/favicon-32x32.png b/docs/typescript/favicons/favicon-32x32.png new file mode 100755 index 0000000..e95c80a Binary files /dev/null and b/docs/typescript/favicons/favicon-32x32.png differ diff --git a/docs/typescript/favicons/favicon.ico b/docs/typescript/favicons/favicon.ico new file mode 100755 index 0000000..216330f Binary files /dev/null and b/docs/typescript/favicons/favicon.ico differ diff --git a/docs/typescript/favicons/pwa-192x192.png b/docs/typescript/favicons/pwa-192x192.png new file mode 100755 index 0000000..94b2ad2 Binary files /dev/null and b/docs/typescript/favicons/pwa-192x192.png differ diff --git a/docs/typescript/favicons/pwa-512x512.png b/docs/typescript/favicons/pwa-512x512.png new file mode 100755 index 0000000..89258a4 Binary files /dev/null and b/docs/typescript/favicons/pwa-512x512.png differ diff --git a/docs/typescript/favicons/tile150x150.png b/docs/typescript/favicons/tile150x150.png new file mode 100755 index 0000000..3d0c760 Binary files /dev/null and b/docs/typescript/favicons/tile150x150.png differ diff --git a/docs/typescript/favicons/tile310x150.png b/docs/typescript/favicons/tile310x150.png new file mode 100755 index 0000000..ed89042 Binary files /dev/null and b/docs/typescript/favicons/tile310x150.png differ diff --git a/docs/typescript/favicons/tile310x310.png b/docs/typescript/favicons/tile310x310.png new file mode 100755 index 0000000..67172b3 Binary files /dev/null and b/docs/typescript/favicons/tile310x310.png differ diff --git a/docs/typescript/favicons/tile70x70.png b/docs/typescript/favicons/tile70x70.png new file mode 100755 index 0000000..31413a2 Binary files /dev/null and b/docs/typescript/favicons/tile70x70.png differ diff --git a/docs/typescript/guide.html b/docs/typescript/guide.html deleted file mode 100644 index 40cade6..0000000 --- a/docs/typescript/guide.html +++ /dev/null @@ -1,3015 +0,0 @@ - - - - - - - -Behavior Graph - - - - - - -
-
-

The Basics

-
-
-

Login button

-
-
Example 1. Login page example
-
-
-

Our first example implements a standard login page.

-
-
-
-Login Page -
-
-
-
    -
  • -

    A login button should be enabled if a valid email and password have been entered.

    -
  • -
  • -

    A valid email has standard email formatting.

    -
  • -
  • -

    A valid password is non-empty.

    -
  • -
  • -

    As the user types into those fields, the enabled state of the login button will update automatically.

    -
  • -
-
-
-
-
-
-

A behavior is a unit of functionality

-
-

Behaviors are the fundamental unit of composition when using Behavior Graph. -They are blocks of code along with the dependency relationships they are involved in.

-
-
-
-
-

Here is the behavior that implements our Login page example. -It gets run whenever the email and password fields change. -It validates those fields and updates the enabled state of the login button accordingly.

-
-
-
Login behavior
-
-
1
-2
-3
-4
-5
-6
-7
-8
-9
-
this.makeBehavior([this.email, this.password], [], (extent: LoginExtent) => {
-    const email = extent.email.value;
-    const password = extent.password.value;
-    const hasPassword = password.length > 0;
-    const loginEnabled = extent.validEmailAddress(email) && hasPassword;
-    extent.sideEffect('enable login button', (extent) => {
-        extent.enableLoginButton(loginEnabled);
-    });
-});
-
-
-
-
-
-
-

The bulk of your code will comprise of many behaviors similar to this one. -Without worrying too much about some unfamiliar details, keep in mind that code inside a behavior is normal code:

-
-
-
    -
  • -

    Conventional programming constructs: property access, method calls, and boolean expressions.

    -
  • -
  • -

    Platform standard API calls for interacting with the environment

    -
  • -
-
-
-
-

A resource is a unit of state

-
-

Resources carry state in a controlled manner. -Resources store information about the system you are modeling.

-
-
-
-
-
Login behavior
-
-
1
-2
-3
-4
-5
-6
-7
-8
-9
-
this.makeBehavior([this.email, this.password], [], (extent: LoginExtent) => {
-    const email = extent.email.value;
-    const password = extent.password.value;
-    const hasPassword = password.length > 0;
-    const loginEnabled = extent.validEmailAddress(email) && hasPassword;
-    extent.sideEffect('enable login button', (extent) => {
-        extent.enableLoginButton(loginEnabled);
-    });
-});
-
-
-
-
-
    -
  • -

    Line 1 of references the email and password properties. -These are both resources.

    -
  • -
  • -

    Lines 2 and 3 access the same properties via the extent object passed into the block.

    -
  • -
-
-
-

email contains the current textual content of the email UI element. -password plays a similar role.

-
-
-
-
-
- -
-

Extents are specialized containers for behaviors and resources. -You must subclass Extent. -On your subclass:

-
-
-
    -
  1. -

    Define resources as properties.

    -
  2. -
  3. -

    Initialize resources in the constructor.

    -
  4. -
  5. -

    Create behaviors in the constructor.

    -
  6. -
-
-
-
-
-

Login page example needs only a single extent, LoginExtent. -email and password are defined as properties.

-
-
-
-
1
-2
-3
-
class LoginExtent extends Extent {
-    email: State<string>;
-    password: State<string>;
-
-
-
-
-

State is a resource subtype for retaining state. -Here they are specialized on the type string for holding the contents of their respective text fields. -Inside the constructor we create the graph elements

-
-
-
-
1
-2
-3
-4
-5
-6
-7
-
constructor(graph: Graph) {
-    super(graph);
-
-    this.email = new State("", this);
-    this.password = new State("", this);
-
-    this.makeBehavior([this.email, this.password], [], (extent: LoginExtent) => {
-
-
-
-
-
-
-
-

State resources retain information

-
-

State is a type of resource. -It is generic on the type of its contents.

-
-
-

Initial contents are supplied in the constructor.

-
-
-

Use the value property to access its contents.

-
-
-

Calling update on it will update those contents. -The contents will remain the same until update is called again with different information.

-
-
-
-

Demands are the resources a behavior depends on

-
-

A behavior has read-only access to a set of resources it depends on called demands. -Behavior Graph uses this dependency information to run the behavior at the correct time.

-
-
-

You must explicitly set the demands on a behavior either when creating a behavior or via the setDemands method.

-
-
-

Accessing the value property from inside a behavior without specifying it as a demand will raise an error.

-
-
-

Calling update on a demanded resource will also raise an error. -It is read-only.

-
-
-
-
-

In order to determine if the login button should be enabled, our login behavior needs access the information stored in the email and password resources.

-
-
-
Login behavior
-
-
1
-2
-3
-4
-5
-6
-7
-8
-9
-
this.makeBehavior([this.email, this.password], [], (extent: LoginExtent) => {
-    const email = extent.email.value;
-    const password = extent.password.value;
-    const hasPassword = password.length > 0;
-    const loginEnabled = extent.validEmailAddress(email) && hasPassword;
-    extent.sideEffect('enable login button', (extent) => {
-        extent.enableLoginButton(loginEnabled);
-    });
-});
-
-
-
-
-
    -
  • -

    Line 1 initializes the behavior with an array containing these resources as demands.

    -
  • -
  • -

    Lines 2 and 3 are able to access the stored contents of email and password via the value property. -This is because they are listed as demands in line 1.

    -
  • -
-
-
-
-
-
-

Input happens via actions

-
-

The environment is everything that is not part of your Behavior Graph subsystem. -In order to track changes to that environment, you program must create new actions via the action method on the graph object. -Inside that you are able to update the contents of resources.

-
-
-
-
-

As the user types into the email and password fields, we want our program to react by updating the enabled state of the login button. -Those UI fields are part of the environment. -So we write handlers for those fields which will create new actions as those fields change.

-
-
-
Login actions
-
-
 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
-10
-11
-
didUpdateEmailField(contents: string) {
-    this.graph.action('update email field', () => {
-        this.loginExtent.email.update(contents, true);
-    });
-}
-
-didUpdatePasswordField(contents: string) {
-    this.graph.action('update password field', () => {
-        this.loginExtent.password.update(contents, true);
-    });
-}
-
-
-
-
-
    -
  • -

    Line 1 is a typical callback method that is called from the UI framework when the email text field is updated.

    -
  • -
  • -

    Line 2 creates a new action block.

    -
  • -
  • -

    Line 3 updates the contents of the email resource using the update method. -This is the same resource instance that is accessed in Login behavior.

    -
  • -
-
-
-
-
- - - - - -
- - -Action blocks are initialized with an optional string called the impulse. -The impulse is a debugging aid to help answer the question, "why is this happening?". -
-
-
-
-

Updating a resource causes its demanding behaviors to be activated

-
-

Calling update on a resource will change the information stored in that resource. -When the value changes, any behavior that demands that resource will be activated. -Activated behaviors are put into an internal queue to run in the correct order.

-
-
-
-
-
    -
  • -

    Each time the user types characters into the email field, the didUpdateEmailField will run, creating a new action block.

    -
  • -
  • -

    When that action block runs, the email resource will update to contain the current contents of the email field.

    -
  • -
  • -

    The Login behavior demands the email resource, so it activates.

    -
  • -
-
-
-
-
-
-

The next activated behavior will run after the current action or behavior completes

-
-

After the current action or behavior block completes, the Behavior Graph will check if any there are any activated behaviors on its internal queue. -If so it will remove the top one from the queue and run it. -This will continue until there are no more activated behaviors on the queue.

-
-
-
-
- -
-
-
-
-
-

Side effects create output in the environment

-
-

While a behavior is running, it may determine that changing circumstances warrant a reaction in the environment. -Create this mechanism for output by calling sideEffect on the current extent.

-
-
-

All interactions with the environment that do something should happen through side effects. -This lets the Behavior Graph runtime postpone changes to the environment until after any state changes.

-
-
-
-
-
Login behavior
-
-
1
-2
-3
-4
-5
-6
-7
-8
-9
-
this.makeBehavior([this.email, this.password], [], (extent: LoginExtent) => {
-    const email = extent.email.value;
-    const password = extent.password.value;
-    const hasPassword = password.length > 0;
-    const loginEnabled = extent.validEmailAddress(email) && hasPassword;
-    extent.sideEffect('enable login button', (extent) => {
-        extent.enableLoginButton(loginEnabled);
-    });
-});
-
-
-
-
-
    -
  • -

    Line 7 creates a side effect.

    -
  • -
  • -

    The next line updates the enabled state of the UI element by making a call directly to the platform user interface API.

    -
  • -
-
-
-
-
- - - - - -
- - -The string parameter to sideEffect is an aid for debugging. -
-
-
-
-

Behavior Graph is a graph

-
-

Behavior Graph diagrams provide a compact visual overview of the elements involved in your system.

-
-
-
-
-

With our actions, resources, behavior, and side effect, Login page example takes on the distinctive characteristics of a graph.

-
-
-
-Login Diagram -
-
-
-
    -
  • -

    email and password rectangles are resources.

    -
  • -
  • -

    The dashed boxes around them are actions.

    -
  • -
  • -

    The dashed box around enable login button is a side effect.

    -
  • -
  • -

    The solid box around it is the behavior. -That behavior demands those resources as indicated by the connecting lines.

    -
  • -
-
-
-
-
-
-

There is a graph instance

-
-

A program will need at least one instance of Graph. -This object connects all behaviors, resources, and extents involved in your system. -It is responsible for running behavior code blocks in the correct order and ensuring relationships are valid.

-
-
-

Create a single instance of Graph and make it available to any object which will work with Behavior Graph code. -Then add your extent instances inside an action and the addToGraph method.

-
-
-
-
-

In the root application code, we create an instance of the LoginExtent and add it to our graph.

-
-
-
-
1
-2
-3
-4
-5
-
this.graph = new Graph();
-this.loginExtent = new LoginExtent(this.graph);
-this.graph.action('new login page', () => {
-    this.loginExtent.addToGraph();
-});
-
-
-
-
-

Line 2 creates a new action on this graph object inside which we add our LoginExtent instance.

-
-
-
-
-
-

An Event is a single run through the graph

-
-

An event begins with the running of an action block. -The behavior graph will continue to run activated behaviors until there are none left. -It will then run side effects in the order they were created. -When there are no remaining side effects, the event will complete.

-
-
-
-
-

Assume the user has just typed a character into the email text field which now contains the letters "sal":

-
-
-
    -
  1. -

    The didUpdateEmailField method is called, which creates a new action.

    -
  2. -
  3. -

    The graph object will run the action block.

    -
  4. -
  5. -

    Inside the action block the email resource is updated to contain the string "sal"/

    -
  6. -
  7. -

    The updated resource activates the login behavior.

    -
  8. -
  9. -

    The action block completes.

    -
  10. -
  11. -

    The graph object sees only one behavior has been activated and runs it.

    -
  12. -
  13. -

    The behavior code block runs, determines email is invalid and creates a side effect to disable the login button.

    -
  14. -
  15. -

    The behavior code block completes.

    -
  16. -
  17. -

    With no more activated behaviors, the graph object runs the only side effect.

    -
  18. -
  19. -

    The side effect block runs the code to disable the login button.

    -
  20. -
-
-
-

This is all part of a single event. -When the user types an additional character a new event will run.

-
-
-
-
-
-
-
-

Getting Deeper

-
-
-

Complete login page example

-
-
Example 2. Complete login page
-
-
-

We can extend our prior example to include the asynchronous interactions for logging in.

-
-
-
-Complete login page -
-
-
-

This Behavior Graph diagram includes the additional elements and relationships to support the following additional features:

-
-
-
    -
  • -

    Clicking on the login button, when enabled, will make a remote API call with the user’s credentials.

    -
  • -
  • -

    While the login API call is being made the button will disable.

    -
  • -
  • -

    Tapping the return key will also initiate a login.

    -
  • -
  • -

    Tapping the return key while the login button is disabled will not login.

    -
  • -
  • -

    If the API call returns an error, the login button will reenable.

    -
  • -
-
-
-
-
-
-

Behaviors are units of state management

-
-

The most common role of a behavior is to synthesize new information based on its demands.

-
-
-

It stores this information in resources called it’s supplies. -These are resources to which it has read-write access.

-
-
-

A behavior can call update and access the value property on any resource that it supplies.

-
-
-

A behavior can supply any number of resources.

-
-
-
-
-

This behavior reacts to changes to the email text field by updating its emailValid resource based on the contents of the email resource.

-
-
-
Login email valid
-
-
1
-2
-3
-4
-5
-6
-
this.emailValid = new State(false, this);
-this.makeBehavior([this.email], [this.emailValid], (extent: this) => {
-    const email = extent.email.value;
-    const emailValid = extent.validEmailAddress(email);
-    extent.emailValid.update(emailValid, true);
-});
-
-
-
-
-
    -
  • -

    Line 1 initializes the emailValid resource, a State resource on the LoginExtent object. -Its initial value is false.

    -
  • -
  • -

    The makeBehavior method includes emailValid in its list of supplied resources in its second parameter.

    -
  • -
  • -

    Line 5 calls update to update the contents of emailValid.

    -
  • -
-
-
-

passwordValid receives a similar treatment.

-
-
-
-
-
-

Resource updates activate behaviors

-
-

The primary reason a behavior runs during any given event is that one or more of its demanded resources has updated.

-
-
-
-
-

As the user types into the email text field, the email resource updates. -When it updates, the behavior that supplies emailValid activates. -It will be run during the same event.

-
-
-

The similar behavior that supplies passwordValid will not activate during this event. -Therefore it will not run. -This is because the password resource did not update.

-
-
-
-
-
-

Updates filter for equality

-
-

update takes an additional parameter indicating whether the update should filter out new values that are the same as the current value. -Passing true in the second parameter will enable this filter. -If the contents are the same, say updating from false to false, then this version of update does nothing. -Therefore no demanding behavior will activate. -Behavior Graph uses the standard platform equality check inside update.

-
-
-

Passing false as the second parameter will perform no additional check. -Using this, any demanding behaviors will always be activated.

-
-
-
-
-
Login email valid
-
-
1
-2
-3
-4
-5
-6
-
this.emailValid = new State(false, this);
-this.makeBehavior([this.email], [this.emailValid], (extent: this) => {
-    const email = extent.email.value;
-    const emailValid = extent.validEmailAddress(email);
-    extent.emailValid.update(emailValid, true);
-});
-
-
-
-
-
    -
  • -

    On line 1, the emailValid resource is initialized with false. -As the user begins to type into the email text field it will not be a valid email.

    -
  • -
  • -

    Line 5 calls update on emailValid. Setting it to false again will do nothing because we filter out the equality. -The login enabling behavior which demands this resource will not activate.

    -
  • -
  • -

    When the user finally types in a valid email, emailValid will change to true, which will activate and subsequently run the login enabling behavior.

    -
  • -
-
-
-
-
- - - - - -
- - -Equality in programming is a nuanced topic, to say the least. -If the default method does not work for you, skip the equality check and perform your own. -
-
-
-
-

Moment resources capture transient knowledge

-
-

In contrast to State resources, Moment resources capture information about what is happening only during the current event. -A button click or a key press are moments.

-
-
-

Moments are instances of Moment.

-
-
-

Calling update on a moment instance inside an action or supplying behavior will capture the idea that it happened.

-
-
-

Querying a moment’s justUpdated property will determine if the moment happened during the current event.

-
-
-

Some moments may contain no information beyond merely happening, such as a button click. -Other moments, such as a successful network response, may also have additional information that you will wish to capture. -A moment instance will be generic on the type of its contents. -Pass in this additional information as a parameter to the update method. -Query this information using the value property.

-
-
-

Moments are transient. -The contents are only available during the event that they happen. -They will be forgotten at the end of the event.

-
-
-
-
-

loginClick and returnKey are both moments that update when the user clicks on the button or taps the return key. -Neither has any additional contents.

-
-
-
Login click
-
-
1
-2
-3
-4
-5
-
loginButtonClicked() {
-    this.graph.action('login button clicked', () => {
-        this.loginExtent.loginClick.update();
-    });
-}
-
-
-
-
-
-
- - - - - -
- - -Behavior Graph diagrams show moments as resources with a cutout in the top right corner. -
-
-
-
-

Moments activate behaviors when they happen

-
-

Similar to a state change in state resources, when a moment happens it is considered updated. -Any behaviors that demand it will activate.

-
-
-

Behaviors that demand moments will frequently check justUpdated to determine how to react during the current event.

-
-
-
-
-

This behavior decides when to log in and updates the logging in state. -loggingIn is a state resource, while loginComplete captures the moment know our login API call has succeeded.

-
-
-
Logging in behavior
-
-
 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
-10
-11
-12
-13
-14
-15
-16
-17
-18
-19
-20
-21
-22
-23
-24
-25
-
this.loginClick = new Moment(this);
-this.returnKey = new Moment(this);
-this.loginComplete = new Moment(this);
-this.makeBehavior([this.loginClick, this.returnKey, this.loginComplete], [this.loggingIn], (extent: this) => {
-    if ((extent.loginClick.justUpdated || extent.returnKey.justUpdated) &&
-        extent.loginEnabled.traceValue) {
-        // Start login
-        extent.loggingIn.update(true, true);
-    } else if (extent.loginComplete.justUpdated &&
-               !extent.loginComplete.value &&
-               extent.loggingIn.value) {
-        // Login failed
-        extent.loggingIn.update(false, true);
-    }
-
-    if (extent.loggingIn.justUpdatedTo(true)) {
-        extent.sideEffect('login api call', (extent: this) => {
-            extent.doLogin(extent.email.value, extent.password.value, (success: boolean) => {
-                extent.action('login call returned', () => {
-                    extent.loginComplete.update(success);
-                });
-            });
-        });
-    }
-});
-
-
-
-
-
    -
  • -

    The first clause of the if statement responds to clicking the login button or pressing the return key to start the login API call.

    -
  • -
  • -

    The second clause responds to the completed network call, putting us in a logged in state.

    -
  • -
  • -

    Lastly if we have just entered the logging in state, we will initiate that API call.

    -
  • -
-
-
-
-
-
-

State changes can be queried

-
-

State resources have a justUpdated property. -It is only true during the event in which a successful update occurs.

-
-
-

For more precision, there are also justUpdatedTo and justUpdatedToFrom methods. -This check can be done in the same behavior that supplies the resource or any behavior that demands it.

-
-
-
-
-
    -
  • -

    Line 9 of Logging in behavior updates the value of loggingIn to true when the user clicks the button or presses the return key.

    -
  • -
  • -

    Line 17 then checks that same resource via justUpdatedTo in order to determine if the system should do the actual side effect of calling the login API method.

    -
  • -
-
-
-
-
-
-

Updates activate behaviors

-
-

A typical behavior graph program will consist of many state and moment resources. -It is useful to be able to talk about the general idea behind "happening" or "changing". -This term is called updating.

-
-
-

When a resource updates, any behaviors that demand it will be activated.

-
-
-

Updates can only be checked for inside a behavior if that behavior demands or supplies that resource. -Doing otherwise is an error

-
-
-
-

Updates can only come from actions or behaviors

-
-

If the update comes from a behavior, that resource must be supplied by that behavior. -A resource may be supplied by only one behavior.

-
-
-

If a resource is not supplied by a behavior may it be updated inside an action.

-
-
-

These rules guarantee that a resource will be updated only once per event.

-
-
-
-
-
-

How it Works

-
-
-

Behavior Graph is a bipartite directed acyclic graph

-
-

The graph of the Behavior Graph contains two node types, resources and behaviors, making it a bipartite graph.

-
-
-

Edges are the links between resources and behaviors.

-
-
-
Example 3. Graph example
-
-
-
-Graph example -
-
-
-
-
-

Specifically this is a dataflow dependency graph which has a few simple rules:

-
-
-
    -
  • -

    Resources can only point to (demanded by) behaviors

    -
  • -
  • -

    Behaviors can only point to (supply) resources

    -
  • -
  • -

    A resource can be demanded by any number of behaviors (B1 demands R2 and B2 demands R2)

    -
  • -
  • -

    A behavior can supply to 0 or more resources (B1 supplies R5 and R4)

    -
  • -
  • -

    A resource can be supplied by either:

    -
    -
      -
    • -

      0 behaviors (R1 has no supplier, therefore it is updated in an action)

      -
    • -
    • -

      1 behavior (R5 is supplied only by B1)

      -
    • -
    -
    -
  • -
  • -

    No cycles are permitted

    -
  • -
-
-
-

These rules combine to guarantee that during any event, each behavior will be run no more than once, and each resource will update in at most one place.

-
-
-
-

Behavior Graph runs code in the correct order

-
-

The value proposition for the Behavior Graph comes down to letting the computer manage control flow. -Control flow means deciding what code should run next.

-
-
-

After completing an action or behavior, the Behavior Graph will select the next behavior off the queue to run. -However there may be multiple behaviors on that queue waiting to run. -Behavior Graph uses a priority queue based on the topological ordering of all the behaviors in the graph.

-
-
-
-
-

We can see how this matters looking at Graph example.

-
-
-
    -
  1. -

    When R1 is updated, the graph knows that B1 should be run next.

    -
  2. -
  3. -

    When R2 is updated however, both B1 and B2 are activated.

    -
  4. -
  5. -

    The graph must run B1 first because B1 may update R5 which is another demand of B2.

    -
  6. -
-
-
-
-
-
-

Graph cycles are not permitted

-
-

Behavior Graph will throw an error when a graph cycle is detected as extents are added to the graph. -However, cycles can be easy to create.

-
-
-
-
-

Referring to Logging in behavior, a potential cyclical error occurs with returnKey:

-
-
-
    -
  1. -

    Pressing the return key, when login is enabled, should put the system in a logging in state.

    -
  2. -
  3. -

    When the system is in a logging in state, the login button should be disabled.

    -
  4. -
  5. -

    When login is disabled, the return key should no longer work.

    -
  6. -
-
-
-

The dependency chain for this looks like: -returnKey → loggingIn behavior → loggingIn → loginEnabled behavior → loginEnabled → loggingIn behavior (cycle)

-
-
-

Our solution is to recognize that when pressing the return key, the system is not interested in what state loginEnabled will enter during that event, but what it was as the event begins.

-
-
-
    -
  • -

    Pressing the return key should not try to log the user in again if loginEnabled is false.

    -
  • -
  • -

    If it is true then the user can log in at which point it will become false.

    -
  • -
-
-
-
-
-
-
-
-

Fixing Problems

-
-
-

State resources have trace values

-
-

Use trace values to break cycles.

-
-
-

Calling traceValue on a state resource inside a behavior will return its contents as they are at the beginning of the event. -If at some point during the same event the contents change from an update, the traceValue will continue to return the value that it was before that update.

-
-
-

Accessing the traceValue of a resource does not require it to be listed in the demands list of the behavior.

-
-
-

It is important to remember that traceValue is different than the prior value. -It is only the prior value if it updated during this event. -After the event ends, traceValue and value will return the same contents.

-
-
-
-
-
Logging in behavior
-
-
 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
-10
-11
-12
-13
-14
-15
-16
-17
-18
-19
-20
-21
-22
-23
-24
-25
-
this.loginClick = new Moment(this);
-this.returnKey = new Moment(this);
-this.loginComplete = new Moment(this);
-this.makeBehavior([this.loginClick, this.returnKey, this.loginComplete], [this.loggingIn], (extent: this) => {
-    if ((extent.loginClick.justUpdated || extent.returnKey.justUpdated) &&
-        extent.loginEnabled.traceValue) {
-        // Start login
-        extent.loggingIn.update(true, true);
-    } else if (extent.loginComplete.justUpdated &&
-               !extent.loginComplete.value &&
-               extent.loggingIn.value) {
-        // Login failed
-        extent.loggingIn.update(false, true);
-    }
-
-    if (extent.loggingIn.justUpdatedTo(true)) {
-        extent.sideEffect('login api call', (extent: this) => {
-            extent.doLogin(extent.email.value, extent.password.value, (success: boolean) => {
-                extent.action('login call returned', () => {
-                    extent.loginComplete.update(success);
-                });
-            });
-        });
-    }
-});
-
-
-
-
-

Line 7 accesses loginEnabled.traceValue to prevent a potential cycle. -It is not listed in the demands and Behavior Graph will not throw an error.

-
-
-

The behavior graph diagram in Complete login page renders the dependency between loginEnabled and the behavior that supplies loggingIn with a dotted line to show the connection.

-
-
-
-
-

In Behavior Graph diagrams, trace value dependencies are drawn as a dotted line and point to the lower portion of the behavior to visually separate them from other dependencies.

-
-
-
-

Use the debug console to track down cycles

-
-

Cycles that span many behaviors and extents are not always obvious. -The console will print the sequence of behaviors and resources that create the cycle. -Use this information to help determine where the chain can be broken.

-
-
-

You can call cycleStringForBehavior on the instance of the Graph to print or step through these objects.

-
-
-
-

Complex behaviors can make it easier to create cycles

-
- - - - - -
- - -Combining many different demands and supplies in the same behavior can be practical and sometimes necessary. -However, these behaviors also make it easier to create graph cycles during the development phase. -Separating out independent functionality into different behaviors can often free up cycles. -
-
-
-
-

Side effect blocks run after all behaviors

-
-

Behaviors may create side effects. -By design, those side effects do not run until there are no more activated behaviors in the queue, ie the end of the event.

-
-
-
-
-
Login Enable
-
-
1
-2
-3
-4
-5
-6
-7
-8
-
this.loginEnabled = new State(false, this);
-this.makeBehavior([this.emailValid, this.passwordValid, this.loggingIn], [this.loginEnabled], (extent: this) => {
-    const enabled = extent.emailValid.value && extent.passwordValid.value && !extent.loggingIn.value;
-    extent.loginEnabled.update(enabled, true);
-    extent.sideEffect('enable login button', (extent: this) => {
-        extent.enableLoginButton(extent.loginEnabled.value);
-    });
-});
-
-
-
-
-

As can be seen from the Complete login page diagram, this behavior has no downstream dependencies and will be the last to be run. -Line 7 creates a side effect which will not be run until after this behavior completes.

-
-
-

Likewise when the user clicks the login button the first time, the side effect on line 18 of Logging in behavior will also not be run until this behavior completes.

-
-
-
-
-

The reason for postponing the running of side effects is to ensure that unstable information doesn’t leak out into the environment. -As a side effect block runs, Behavior Graph must relinquish control flow. -That code may call out to some external library which subsequently calls back in to read the current value of a resource. -If we were in the behavior phase of an event, any number of resources may still need updating to new values. -The resources in the system are only in a stable state after all activated behaviors have been run.

-
-
-
-

Side effect blocks are run in the order they are created

-
-

Most systems will need some ability to maintain sequential dependencies between the code run in side effects. -For example one behavior may create the side effect for initializing a video player. -A separate behavior may create a side effect which tells the video player to play. -It is necessary to ensure the video player is created before it is told to play.

-
-
-
-
-

In Complete login page, the login call will be made before the button is disabled when the user clicks the login button. -This is because the two behaviors that create those side effects will be run in that order.

-
-
-
-
-

If your code has implicit dependencies between side effect blocks, you can make them explicit by creating a dependency between their creating behaviors. -Do this by creating a resource which is supplied by the behavior that creates the first side effect and demanded by the behavior that creates the second side effect.

-
-
-
-

Events are serialized

-
-

It is possible for an action to be created while another event is currently executing when a side effect block leads to a new action and there are still side effects remaining. -However, interrupting the current event to run another one could lead to inconsistent results. -It is necessary for the entire event to work as a single transaction.

-
-
-

When this happens:

-
-
-
    -
  1. -

    The new action will be placed in a queue and the current event will continue to run any remaining side effects of current event at the action creation point.

    -
  2. -
  3. -

    When the current event completes, the newly queued up action will create an event and run until completion.

    -
  4. -
  5. -

    This will continue until there are no more queued actions, at which point the code will continue.

    -
  6. -
-
-
-
-
-
Logging in behavior
-
-
 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
-10
-11
-12
-13
-14
-15
-16
-17
-18
-19
-20
-21
-22
-23
-24
-25
-
this.loginClick = new Moment(this);
-this.returnKey = new Moment(this);
-this.loginComplete = new Moment(this);
-this.makeBehavior([this.loginClick, this.returnKey, this.loginComplete], [this.loggingIn], (extent: this) => {
-    if ((extent.loginClick.justUpdated || extent.returnKey.justUpdated) &&
-        extent.loginEnabled.traceValue) {
-        // Start login
-        extent.loggingIn.update(true, true);
-    } else if (extent.loginComplete.justUpdated &&
-               !extent.loginComplete.value &&
-               extent.loggingIn.value) {
-        // Login failed
-        extent.loggingIn.update(false, true);
-    }
-
-    if (extent.loggingIn.justUpdatedTo(true)) {
-        extent.sideEffect('login api call', (extent: this) => {
-            extent.doLogin(extent.email.value, extent.password.value, (success: boolean) => {
-                extent.action('login call returned', () => {
-                    extent.loginComplete.update(success);
-                });
-            });
-        });
-    }
-});
-
-
-
-
-
    -
  1. -

    When the user clicks the login button, this behavior that logs the user in will activate and run.

    -
  2. -
  3. -

    Line 19 will be run during the side effect phase of the event.

    -
  4. -
  5. -

    It is possible this external login method may immediately call the completion block which will then create a new action on line 21.

    -
  6. -
  7. -

    The first event created by clicking the login button is still running. It needs to complete before running this new login complete action. So it will place the login complete action in the queue and continue to its next side effect which will disable the login button.

    -
  8. -
  9. -

    After running the remaining side effect, the first event will complete, and the code inside the action block created on line 21 will run.

    -
  10. -
  11. -

    This new event will run to completion.

    -
  12. -
  13. -

    Finally the stack from the initial side effect created on line 18 will complete and unwind.

    -
  14. -
-
-
-
-
-
-

Events are synchronized onto the same thread

-
-

Behavior Graph does not handle concurrency. -All events are serialized onto the same thread which can be specified when initializing the Graph object.

-
-
-
-

Actions blocks are run synchronously

-
-

When the environment creates a new action, that action block and the entire event will be run synchronously. -The line of code that follows the action will not be run until the event created by that action has run to completion.

-
-
-

This default matches imperative programming expectations. -If a line of code following the action block attempts to read the value of a resource, you can expect it to have been updated accordingly. -And all side effect blocks created as a result of that action will be run before that next line of code.

-
-
-

As mentioned previously, however, there may already be a running event or queued actions when a new action is created. -Many events may get run between the time an action is created and when its own corresponding event is run. -These events will all run to completion before the code that creates the action returns.

-
-
-
-
-
Login click
-
-
1
-2
-3
-4
-5
-
loginButtonClicked() {
-    this.graph.action('login button clicked', () => {
-        this.loginExtent.loginClick.update();
-    });
-}
-
-
-
-
-

This method creates a new action on line 2; however, we cannot guarantee that the code inside the action is run immediately. -The Behavior Graph does guarantee that all events will have completed before proceeding past line 4 and exiting this method.

-
-
-
-
-
-

Side effects can’t be strictly enforced

-
-

You should always create a side effect when you wish to output information to the environment. -However, strictly enforcing this policy would require wrapping every possible type of output.

-
-
-

Instead, the code in behavior blocks is normal imperative code. -Technically anything is possible. -In order to manage control flow, the Behavior Graph cannot handle a new synchronous action while still running behaviors during an event.

-
-
-

If, from inside a behavior (not side effect), you create a synchronous action or call some code that eventually leads to a synchronous action, Behavior Graph will raise an error.

-
-
-

Also, if, from inside a behavior (not side effect), you call some code that eventually leads to accessing a non-demanded resource, Behavior Graph will raise an error.

-
-
-

Instances of this error can be subtle. -Be careful when working with anything that may affect the environment directly from a behavior. -This includes memory allocation, destructors, exceptions, or any other impure code.

-
-
-
-

Action blocks can have optional synchrony (but not the default)

-
-

The safest way to create a new action is to opt out of synchrony. -To do this call actionAsync.

-
-
-

This method of creating a new action will run the action and associated event immediately if there are no events running currently. -Otherwise, it will put them on a queue to be run after the current event (and any additional queued actions) are run, returning up the call stack.

-
-
-

Prefer this variation whenever possible.

-
-
-
-
-

A better implementation of the login side effect in Logging in behavior would opt out of synchrony.

-
-
-
-
1
-2
-3
-4
-5
-6
-7
-
extent.sideEffect('login api call', (extent: this) => {
-    extent.doLogin(extent.email.value, extent.password.value, (success: boolean) => {
-        extent.actionAsync('login call returned', () => {
-            extent.loginComplete.update(success);
-        });
-    });
-});
-
-
-
-
-

Line 3 uses the optional asynchronous form when creating a new action. -Opting out of synchrony here means the side effect created on line 1 will exit its call stack before starting the event associated with this new action.

-
-
-
-
-
-

Events have sequence numbers

-
-

When a resource is updated it retains a reference to the instance of GraphEvent in which it was last updated. -These event instances have a monotonically increasing sequence number (every event run is +1 the prior event). -You can use these sequence numbers to compare multiple resources to determine the order they were updated.

-
-
-

If this event property is accessed inside a behavior its resource must be declared as a demand. -There is a corresponding traceEvent available if such a dependency creates a cycle.

-
-
-
-
-

We can compare the timestamps of the password and email resources to see if one were updated more recently.

-
-
-
-
1
-2
-3
-
emailChangedSincePassword() : boolean {
-    return this.email.event.sequence > this.password.event.sequence;
-}
-
-
-
-
-
-
-
-

Events have timestamps

-
-

Each event also gets a timestamp when the event is run.

-
-
-

It is a common programing idiom to interweave code with timestamp parameters in order to facilitate testing and instrumentation. -By providing this information as part of each event, behaviors and side effects have easy access without the typical crosscutting burden.

-
-
-
-
-

We can reference when the login happened in some security auditing code.

-
-
-
-
1
-2
-3
-
loginCompletedWhen() : Date {
-    return this.loginComplete.event.timestamp;
-}
-
-
-
-
-
-
-

For testing purposes you can mock out the date provider of the graph object in one place. -Override the dateProvider property with your own implementation of BehaviorGraphDateProvider.

-
-
-
-
-
-

Architecting Systems

-
-
-

Video Chat Example

-
-

We will now change our example app to a hypothetical but familiar video chat experience.

-
-
-
Example 4. Video chat
-
-
-
-Video chat -
-
-
-
    -
  • -

    There will be a grid of squares showing the live video feed for a number of participants.

    -
  • -
  • -

    Each participant will have a small button overlay for toggling their mute.

    -
  • -
  • -

    Each participant will have a small button overlay to pin that participant.

    -
  • -
  • -

    When a participant is pinned, that ui will appear larger than the others.

    -
  • -
  • -

    Only one participant can be pinned at the same time. -If there is already a pinned participant, tapping on the pin button of another will unpin the first and pin the new one.

    -
  • -
-
-
-

The Behavior Graph diagram for this functionality looks like this

-
-
-
-Video Chat Diagram -
-
-
-
-
-
-

Extents capture lifetimes

-
-

Extents can come and go, reflecting the range of time they play a useful role in your system.

-
-
-
-
-

In the Video chat example, we will have two types of extents.

-
-
-

A single ChatExtent will be created and added to the graph every time we initiate a new chat. -It reflects the lifetime of the video chat. -Once the chat is over, it no longer plays a functioning roll and can be removed from the graph.

-
-
-
-
1
-
class ChatExtent extends Extent {
-
-
-
-
-

A ParticipantExtent will be created each time a new participant joins the video chat. -Each chat may have multiple participants. -They may come and go at any time during the video chat.

-
-
-
-
1
-
class ParticipantExtent extends Extent {
-
-
-
-
-
-
-
-

Extents exclusively own behaviors and resources

-
-

Behaviors and resources always belong to one and only one extent.

-
-
-

They do not exist independently from their owning extent.

-
-
-

You cannot create a resource on one extent and assign it to a member variable on another.

-
-
-
-

Resources are named and assigned to extent member variables

-
-

You will regularly refer to resources by name via their extent.

-
-
-
-
-

Our mute functionality requires some resources which we declare as properties on the ParticipantExtent.

-
-
-
-
1
-2
-
muteTap: Moment;
-muted: State<boolean>;
-
-
-
-
-
    -
  • -

    muteTap is a moment resource that tracks the user tapping on the mute button.

    -
  • -
  • -

    muted is a state resource that captures the local muted status of that participant.

    -
  • -
-
-
-

We will initialize and assign them in the constructor along with the behavior that links to them.

-
-
-
Mute behavior
-
-
 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
-10
-11
-12
-13
-
this.muteTap = new Moment(this);
-this.muted = new State(false, this);
-this.makeBehavior([this.muteTap], [this.muted], (extent: this) => {
-    if (extent.muteTap.justUpdated) {
-        extent.muted.update(!extent.muted.value, true);
-        if (extent.muted.justUpdated) {
-            extent.sideEffect('mute toggle', (extent: this) => {
-                extent.muteParticipant(extent.muted.value);
-                extent.updateMuteUI(extent.muted.value);
-            });
-        }
-    }
-});
-
-
-
-
-

On line 3 we refer to their member variables directly when specifying the linked resources for this behavior. -On almost every line thereafter we refer to them by name via their extent.

-
-
-
-
-
-

Behaviors are typically unnamed

-
-

Initialize behaviors via the Extent factory method makeBehavior.

-
-
-

Behaviors can have their linked resources redefined dynamically. -You can optionally save the results of that method to a member variable if you wish to do this.

-
-
-
-
-
-
1
-
this.muteBehavior = this.makeBehavior([this.muteTap], [this.muted], //...
-
-
-
-
-
-
-
-

Behaviors and resources are added to and removed from a graph via extents

-
-

Add behaviors and resources to the graph by adding their owning extent. -Use the addToGraph method of the extent object.

-
-
-

Adding and removing extents must happen during an event– either inside an action or behavior. -Doing otherwise will raise an error.

-
-
-

Behaviors which have not yet been added to the graph will not run. -Updating a resource which has not yet been added to the graph will raise an error.

-
-
-
-
-

During a video chat, our system will need to handle participants joining and leaving. -We will model this by adding and removing instances of ParticipantExtent to the graph.

-
-
-

To capture this functionality, we will have a behavior that demands resources indicating that a participant has joined or left. -When these moments happen our behavior can either create and add the new extent or remove the old one.

-
-
-
Add participants
-
-
 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
-10
-11
-12
-13
-14
-15
-16
-17
-18
-19
-20
-21
-22
-
this.participantJoined = new Moment(this);
-this.participantDisconnected = new Moment(this);
-this.participants = new State(new Map(), this);
-this.makeBehavior([this.participantJoined, this.participantDisconnected], [this.participants], (extent : this) => {
-    if (extent.participantJoined.justUpdated) {
-        const participantId = extent.participantJoined.value;
-        const participant = new ParticipantExtent(extent.graph, participantId, extent);
-        participant.addToGraph();
-        extent.participants.value.set(participantId, participant);
-        extent.participants.update(extent.participants.value, false);
-    }
-
-    if (extent.participantDisconnected.justUpdated) {
-        const participantId = extent.participantDisconnected.value;
-        const participant = extent.participants.value.get(participantId);
-        participant.removeFromGraph();
-        extent.participants.value.delete(participantId);
-        extent.participants.update(extent.participants.value, false);
-
-    }
-
-});
-
-
-
-
-

Each time a new participant joins our video chat, the moment resource participantJoined will update, activating this behavior. -In response we will create a new instance of ParticipantExtent on line 8. -We add it to the graph on the next line.

-
-
-

If the participant later disconnects we can remove it’s functionality from the graph. -Line 17 removes it from the graph.

-
-
-
-
-

Once an extent has been removed from the graph its elements will be removed and unlinked from any other elements still in the graph. -A removed behavior will no longer activate in response to resources it demanded. -A removed resource will no longer activate behaviors and updating it will result in an error.

-
-
-
-

Behaviors always activate in the same event that their extent is added to a graph

-
-

When programming a behavior it is important to remember that it will get run at this time. -Use this to set initial values on state resources when information is not available at initialization time.

-
-
-
-

Extents are the execution context for behaviors and sideEffects

-
-

Extents are reference objects. -They enable code inside behaviors and side effects to interact with other graph elements or the environment. -The extent parameter passed into behaviors and side effects is this point of reference.

-
-
- - - - - -
- - -Most object oriented languages predefine self or this to serve a similar role inside methods. -
-
-
-
-
-
Mute behavior
-
-
 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
-10
-11
-12
-13
-
this.muteTap = new Moment(this);
-this.muted = new State(false, this);
-this.makeBehavior([this.muteTap], [this.muted], (extent: this) => {
-    if (extent.muteTap.justUpdated) {
-        extent.muted.update(!extent.muted.value, true);
-        if (extent.muted.justUpdated) {
-            extent.sideEffect('mute toggle', (extent: this) => {
-                extent.muteParticipant(extent.muted.value);
-                extent.updateMuteUI(extent.muted.value);
-            });
-        }
-    }
-});
-
-
-
-
-

Here we can see nearly every single line in both the behavior and the side effect utilize their extent parameter to refer to resources and call methods.

-
-
-
-
-
- -
-

Frequently information stored in a resource will outlive the behaviors that react to changes in that information. -To enable this, a behavior can demand or supply resources from extents different from their owning extent.

-
-
-
-
-

In our Video chat, pinning one participant means unpinning the previous one if available. -The resource which can track which participant is currently pinned must outlive any particular participant.

-
-
-

The central ChatExtent has a resource pinnedParticipant that stores a reference to the currently pinned ParticipantExtent. -Each ParticipantExtent instance has a behavior that demands that resource.

-
-
-
-
 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
-10
-11
-
this.makeBehavior([this.chatExtent.pinnedParticipant], null, (extent: this) => {
-    if (extent.chatExtent.pinnedParticipant.justUpdatedTo(extent)) {
-        extent.sideEffect('show as pinned', (extent: this) => {
-            extent.updatePinUI(true);
-        });
-    } else if (extent.chatExtent.pinnedParticipant.justUpdatedFrom(extent)) {
-        extent.sideEffect('show as normal', (extent: this) => {
-            extent.updatePinUI(false);
-        });
-    }
-});
-
-
-
-
-
    -
  • -

    Line 1 demands the common pinnedParticipant on the ChatExtent instance stored in the member variable chatExtent.

    -
  • -
  • -

    We wish for the UI to draw the pinned participant larger than the others. -The first clause of the if statement, checks to see if the pinnedParticipant became this extent and creates a side effect to enact that change.

    -
  • -
  • -

    The second clause checks if the pinned participant is no longer this extent, returning it to normal size.

    -
  • -
-
-
-

Because each ParticipantExtent instance demands this central resource, updating that one resource will automatically cause this behavior in each participant to update its respective UI during the same event.

-
-
-
-
-
- -
-

Many applications naturally organize into a hierarchy of lifetimes. -These different lifetimes should be modeled with extents.

-
-
-

The parent extent should own a state resource containing a collection of child extents.

-
-
-
-
-
Add participants
-
-
 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
-10
-11
-12
-13
-14
-15
-16
-17
-18
-19
-20
-21
-22
-
this.participantJoined = new Moment(this);
-this.participantDisconnected = new Moment(this);
-this.participants = new State(new Map(), this);
-this.makeBehavior([this.participantJoined, this.participantDisconnected], [this.participants], (extent : this) => {
-    if (extent.participantJoined.justUpdated) {
-        const participantId = extent.participantJoined.value;
-        const participant = new ParticipantExtent(extent.graph, participantId, extent);
-        participant.addToGraph();
-        extent.participants.value.set(participantId, participant);
-        extent.participants.update(extent.participants.value, false);
-    }
-
-    if (extent.participantDisconnected.justUpdated) {
-        const participantId = extent.participantDisconnected.value;
-        const participant = extent.participants.value.get(participantId);
-        participant.removeFromGraph();
-        extent.participants.value.delete(participantId);
-        extent.participants.update(extent.participants.value, false);
-
-    }
-
-});
-
-
-
-
-

In our Video chat, the lifetime of each participant is necessarily bounded by the lifetime of the entire chat.

-
-
-

On our ChatExtent we create a participants resource to hold on to them. -This state resource holds a dictionary which maps a participant id string to each participant extent.

-
-
-
-
1
-
participants: State<Map<string, ParticipantExtent>>;
-
-
-
-
-

In the behavior that supplies this resource, we update it any time a participant joins or disconnects.

-
-
-

It is worth noting how we update the participants resource in this behavior.

-
-
-
    -
  1. -

    On lines 10 and 18 we directly manipulate the stored dictionary.

    -
  2. -
  3. -

    On the following lines lines 11 and 19, we update using the same dictionary instance and skipping the equality check. -By skipping this equality check, we activate any behaviors which demand the resource while also keeping the same collection. -If we did not skip the equality check, the state resource would recognize that the collection was the same instance and make no update.

    -
  4. -
-
-
-
-
-
- -
-

Behaviors may link to resources in other extents. -Those extents may come and go. -Therefore it is necessary to change their links separately from when those behaviors were initialized and added to the graph.

-
-
-

You may call setDemands and setSupplies on a behavior to change those links. -Once that behavior has been added to the graph, you can only call those methods from inside an action or behavior block.

-
-
-

It is an error to modify a behavior’s links during an event if that behavior has already run during that event. -To prevent this, the behavior that modifies the links should supply a special resource which the Behavior Graph will use for proper ordering. -The behavior which has its links modified should demand this ordering resource.

-
-
-
-
-

To fully implement our pinning functionality, there will be a pinTap moment resource on each ParticipantExtent.

-
-
-
-
1
-
pinTap: Moment;
-
-
-
-
-

There will also be a behavior in the ChatExtent to decide which participant should be pinned. -This behavior demands the pinTap in each ParticipantExtent in order to be activated whenever any of those resources is updated. -However, because participants can come and go, we will not have access to all of these resources at initialization time. -So we will leave them out initially in the demands list when we define our pinned behavior.

-
-
-
Pinned Behavior
-
-
 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
-10
-11
-12
-13
-14
-15
-
this.pinnedParticipant = new State(null, this);
-this.makeBehavior([this.participants, this.participantsRelink], [this.pinnedParticipant], (extent: this) => {
-    const currentPinned = extent.pinnedParticipant.value;
-    let newPinned: ParticipantExtent = null;
-    for (let participant of extent.participants.value.values()) {
-        if (participant.pinTap.justUpdated) {
-            newPinned = participant;
-            break;
-        } else if (participant === currentPinned) {
-            newPinned = currentPinned;
-        }
-    }
-
-    extent.pinnedParticipant.update(newPinned, true);
-});
-
-
-
-
-
    -
  • -

    On line 6, we iterate through each ParticipantExtent instance in the participants resource.

    -
  • -
  • -

    The next lines inspect the pinTap resource on each extent to determine if the user tapped on one or if it should maintain the current pinned participant.

    -
  • -
-
-
-

At this point however, the behavior will not get run when a pinTap resource is updated. -Additionally it will be an error for it to access the pinTap resources because it does not demand them. -We will introduce an additional behavior which updates these demands as the participants change.

-
-
-
-
 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
-10
-
this.participantsRelink = new Resource(this);
-this.makeBehavior([this.participants], [this.participantsRelink], (extent: this) => {
-    let demands = [];
-    demands.push(extent.participants);
-    demands.push(extent.participantsRelink);
-    for (let participant of extent.participants.value.values()) {
-        demands.push(participant.pinTap);
-    }
-    extent.pinnedParticipant.suppliedBy.setDemands(demands);
-});
-
-
-
-
-

Each time a new participant is added or removed (updating the participants resource), this behavior will activate and update the demands of Pinned Behavior.

-
-
-
    -
  • -

    On lines 4 and 5, participants and participantsRelink are added to the array. -They are added because they are part of the default list of demands when Pinned Behavior was initialized.

    -
  • -
  • -

    Next we iterate through each ParticipantExtent instance and add its pinTap resource to the array.

    -
  • -
  • -

    Lastly line 9 updates the demands of that behavior.

    -
  • -
-
-
-

Note the use of participantsRelink resource. -It is of the base type Resource which has limited functionality. -This is our ordering resource. -It has no value and is not updated. -It only exists to ensure that the demands of the pinnedBehavior are updated before the behavior itself is run.

-
-
-
-
-
-

Supplies can also be relinked dynamically

-
-

It is less useful in practice. -Occasionally you may wish to have the behavior on one of many child extents update a resource on the parent level. -As these extents come and go, you may need to designate a new supplier.

-
-
-
- -
-

When the demands of a behavior change, that behavior is activated and run to ensure it is fully taking into account its current set of demands.

-
-
-

When a resource is supplied by a new behavior any behaviors that demand that resource will activate.

-
-
-
-

Removed resources and behaviors are automatically removed from demands and supplies

-
-

Whenever an extent is removed from the graph all its resources and behaviors will also be removed. -Any remaining resources and behaviors will have their links to the removed elements severed.

-
-
-
-

Removed behaviors will not run in the event they are removed

-
-

If an activated behavior is removed before it is run, it will not be run.

-
-
-
-

A program may have multiple instances of a graph

-
-

A program or library can have any number of independent instances of a Graph. -Behaviors and resources cannot link across graph instances. -Extents cannot migrate between graph instances.

-
-
-
-

Independent graphs may communicate through message passing

-
-

One graph may pass information to another by creating a side effect on one which creates a new action on the other.

-
-
-
-
-
- - - - \ No newline at end of file diff --git a/docs/typescript/images/graph_example.png b/docs/typescript/images/graph_example.png new file mode 100644 index 0000000..d0743d9 Binary files /dev/null and b/docs/typescript/images/graph_example.png differ diff --git a/docs/typescript/images/login-intro-graph.svg b/docs/typescript/images/login-intro-graph.svg new file mode 100644 index 0000000..41a0daf --- /dev/null +++ b/docs/typescript/images/login-intro-graph.svg @@ -0,0 +1,147 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Produced by OmniGraffle 7.18.4\n2021-04-07 19:15:33 +0000 + + Login Graph + + + Temperature + + + + + Login Enabled + Behavior + + + + + + + + + + Logging In + Behavior + + + + + + loginClick + + + + + + + + + + + + + + + loggingIn + + + + + + + + + + + + + + + password + + + + + + + + + + email + + + + + + + + + + + + + + Login + + + + + + + loginEnabled + + + + + + + + + + + Login Button + Enabled + + + + + diff --git a/docs/typescript/images/login-ui-2.svg b/docs/typescript/images/login-ui-2.svg new file mode 100644 index 0000000..a78dae1 --- /dev/null +++ b/docs/typescript/images/login-ui-2.svg @@ -0,0 +1,69 @@ + + + + + + + + + + + Produced by OmniGraffle 7.18.4\n2021-04-07 17:51:22 +0000 + + Login Screen + + Layer 1 + + + + + + + + + + + Excellent Application + + + + + + + Customer Login + + + + + Email + + + + + + + Login + + + + + + + sal897@yahoo.com + + + + + + + ********* + + + + + Password + + + + + diff --git a/docs/typescript/images/login_multipage.png b/docs/typescript/images/login_multipage.png new file mode 100644 index 0000000..6ff11f1 Binary files /dev/null and b/docs/typescript/images/login_multipage.png differ diff --git a/docs/typescript/images/login_simple_diagram.png b/docs/typescript/images/login_simple_diagram.png new file mode 100644 index 0000000..7447e95 Binary files /dev/null and b/docs/typescript/images/login_simple_diagram.png differ diff --git a/docs/typescript/images/login_ui.png b/docs/typescript/images/login_ui.png new file mode 100644 index 0000000..28eb9bb Binary files /dev/null and b/docs/typescript/images/login_ui.png differ diff --git a/docs/typescript/images/login_ui_complete.png b/docs/typescript/images/login_ui_complete.png new file mode 100644 index 0000000..1731bcd Binary files /dev/null and b/docs/typescript/images/login_ui_complete.png differ diff --git a/docs/typescript/images/thermostat-heat.svg b/docs/typescript/images/thermostat-heat.svg new file mode 100644 index 0000000..b054f3a --- /dev/null +++ b/docs/typescript/images/thermostat-heat.svg @@ -0,0 +1,143 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Produced by OmniGraffle 7.18.4\n2021-04-07 18:44:20 +0000 + + TempSet + + + Heat + + + + + Heating + Behavior + + + + + + + + + Current + Temperature + + + + + + + + + + + + + + + + + Heating + Equipment + + + + + + + + + + + + + + + Temperature + + + + + Temperature + Behavior + + + + + + Up Button + Press + + + + + + + + + + + + + + + Desired Temperature + Resource + + + + + + Down Button + Press + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/typescript/images/thermostat-temp.svg b/docs/typescript/images/thermostat-temp.svg new file mode 100644 index 0000000..0e6c22c --- /dev/null +++ b/docs/typescript/images/thermostat-temp.svg @@ -0,0 +1,94 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Produced by OmniGraffle 7.18.4\n2021-04-07 18:45:51 +0000 + + TempSet + + + Temperature + + + + + Temperature + Behavior + + + + + + Up Button + Press + + + + + + + + + + + + + + + Desired Temperature + Resource + + + + + + Down Button + Press + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/typescript/images/thermostat-ui.png b/docs/typescript/images/thermostat-ui.png new file mode 100644 index 0000000..f48dc02 Binary files /dev/null and b/docs/typescript/images/thermostat-ui.png differ diff --git a/docs/typescript/images/thermostat-wall.svg b/docs/typescript/images/thermostat-wall.svg new file mode 100644 index 0000000..6459b00 --- /dev/null +++ b/docs/typescript/images/thermostat-wall.svg @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + Produced by OmniGraffle 7.18.4\n2021-04-06 22:49:36 +0000 + + Thermostat + + Layer 1 + + + + + + + + Tempwell + + + + + + + + + + + 65° + + + + + 69° + + + + + Current + + + + + Heat + + + + + + + + + + + + Up + + + + + + + + + + + Down + + + + + + + + + diff --git a/docs/typescript/images/todolist.png b/docs/typescript/images/todolist.png new file mode 100644 index 0000000..b908776 Binary files /dev/null and b/docs/typescript/images/todolist.png differ diff --git a/docs/typescript/images/video_chat_diagram.png b/docs/typescript/images/video_chat_diagram.png new file mode 100644 index 0000000..beda14b Binary files /dev/null and b/docs/typescript/images/video_chat_diagram.png differ diff --git a/docs/typescript/images/video_chat_ui.png b/docs/typescript/images/video_chat_ui.png new file mode 100644 index 0000000..73e31ca Binary files /dev/null and b/docs/typescript/images/video_chat_ui.png differ diff --git a/docs/typescript/index.html b/docs/typescript/index.html new file mode 100644 index 0000000..1bd67ee --- /dev/null +++ b/docs/typescript/index.html @@ -0,0 +1,374 @@ + + + + + + + + + + + + + + + + + + + + + +Behavior Graph + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+
+
+
+ + +
+ + + + + +
+

Behavior Graph

+ + +

Behavior Graph is a software architecture and state management library. It greatly enhances your ability to write complex user facing software and control systems. Broadly speaking, it belongs to the category of libraries which includes Redux, MobX, Rx (Reactive Extensions), and XState. It works by providing a specialized unit of composition which we call the behavior. Behaviors are simple blocks of code together with their dependency relationships.

+

Is it any good?

+

Yes

+

Highlights

+
    +
  • Minimal boilerplate
  • +
  • Scales from the simple to the very complex
  • +
  • Incremental adoption: works alongside existing code and frameworks
  • +
  • Handles state, events, and effects all in one
  • +
  • Multi-platform (Javascript/Typescript, Kotlin, Objective-C, Swift)
  • +
+

We developed Behavior Graph to address our own complexity challenges while building an iOS video playing library which is used internally throughout the suite of native Yahoo mobile apps. After years of development and production usage, it has proven to be incredibly competent at scale. We have since ported it to multiple languages including Javascript/Typescript. It is less than 1500 lines of code and contains no external dependencies.

+

Behavior Graph will particularly appeal to anyone with a willingness to rethink how we write software applications.

+

What does it look like?

+

The below block of code implements a simple counter using Behavior Graph. +It can increment the counter or reset it back to zero.

+

About 70% of the concepts you need to work with Behavior Graph are contained in this one example.

+ +
this.increment = this.moment();
+this.reset = this.moment();
+this.counter = this.state(0);
+
+this.behavior()
+    .demands(this.increment, this.reset)
+    .supplies(this.counter)
+    .runs(this => {
+        if (this.increment.justUpdated) {
+            this.counter.update(this.counter.value + 1);
+        } else if (this.reset.justUpdated) {
+            this.counter.update(0);
+        }
+    });
+

A typical Behavior Graph program consists of dozens or hundreds of behaviors like this, each with its own responsibilities. +The Behavior Graph library then ensures these behaviors are correctly specified and runs them at the correct time and in the correct order. +At scale this is shockingly effective.

+

Is it for me?

+

Behavior Graph is a general purpose library which you can use to organize the event driven logic in any program. +It should also be of interest to anyone with an interest in software engineering and architectures.

+

Specifically if you are working on any of these categories, you should definitely consider it:

+
    +
  • Web apps
  • +
  • Mobile apps
  • +
  • Desktop Applications
  • +
  • User Interfaces
  • +
  • Control Systems
  • +
  • Robots
  • +
  • Games
  • +
+

Learning Behavior Graph

+

While there are only a handful of basic concepts in Behavior Graph, it does require a shift in thinking. +We recommend you start with the Quick Start then work through the Tutorials. +They will help you understand how the pieces fit together.

+ +
+ + + + + + + + +
+ + +
+
+ Quick Start +
+

+
+ + +
+
+ Why Behavior Graph? +
+

+
+ + +
+
+ Code Example +
+

+
+ + +
+
+ API +
+

+
+ + +
+
+ Related Work +
+

+
+ + +
+
+ Questions and Feedback +
+

+
+ + +
+ + + + +
+ +
+
+
+ +
+
+
+
+ +
+
+ +
+
+ © 2022 Yahoo All Rights Reserved + + + + +
+
+
+
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/typescript/index.xml b/docs/typescript/index.xml new file mode 100644 index 0000000..ff683c0 --- /dev/null +++ b/docs/typescript/index.xml @@ -0,0 +1,16 @@ + + + Behavior Graph – Behavior Graph + https://yahoo.github.io/bgdocs/docs/typescript/ + Recent content on Behavior Graph + Hugo -- gohugo.io + + + + + + + + + + diff --git a/docs/typescript/intro.html b/docs/typescript/intro.html deleted file mode 100644 index 4cc49f5..0000000 --- a/docs/typescript/intro.html +++ /dev/null @@ -1,1169 +0,0 @@ - - - - - - - -Behavior Graph - - - - - - -
- -
-

Safe Mutable State

-
-
-

Behavior Graph is a software library that greatly enhances our ability to program user facing software and control systems. -Programs of this type quickly scale up in complexity as features are added. Behavior Graph directly addresses this complexity by shifting more of the burden to the computer. -It works by offering the programmer a new unit of code organization called a behavior. -Behaviors are blocks of code enriched with additional information about their stateful relationships. -Using this information, Behavior Graph enforces safe use of mutable state, arguably the primary source of complexity in this class of software. -It does this by taking on the responsibility of control flow between behaviors, ensuring they are are run at the correct time and in the correct order.

-
-
-

State

-
-

It helps to understand why user facing software, control systems, and similar programs present a particular challenge.

-
-
-

We define these systems by three primary characteristics:

-
-
-
    -
  1. -

    Asynchronous: inputs happen over a period of time

    -
  2. -
  3. -

    Event-driven: outputs occur over time in response to inputs

    -
  4. -
  5. -

    Stateful: outputs depend on a history of prior inputs

    -
  6. -
-
-
-

A thermostat controlling the temperature in a house is an example:

-
-
-
-Login page -
-
-
-
    -
  1. -

    It runs continuously, responding to temperature changes as well as button presses in order to operate the heating equipment.

    -
  2. -
  3. -

    Button presses will result in changes to the display.

    -
  4. -
  5. -

    Button presses which set the desired temperature will determine when the heating equipment turns on in the future.

    -
  6. -
-
-
-

The challenge comes from the large number of different inputs where order and history matter. -A sequence of 10 presses on our Up and Down buttons can occur in over 1000 different ways. -An interface that accepts 10 different types of input over a sequence of 10 events means we are facing 10 billion possible arrangements. -And that is a tiny fraction of what a real user facing application is typically up against.

-
-
-

The solution comes from the fact that we only need to remember just enough information to make decisions in the future. -Instead of remembering each button press, we simply remember a desired temperature and update it as inputs happen. -We don’t care which sequence of button presses gets us to 68 degrees. -To our program they are all the same. -We call this compressed historical information state. -With state we can compress 10 billion button presses into a single number.

-
-
-

Inputs lead to state changes. -Pressing the Up and Down button changes the desired temperature state. -State changes lead to outputs. -Changing the desired temperature means the disply will change. -State changes also often lead to other state changes as our program grows in features. -When the desired temperature changes, the desired state of the heating equipment may change. -(And when that desired state of the heating equipment changes, our program will output to turn on or off the heating equipment.)

-
-
-

A correctly functioning program will have a natural dependency graph between inputs, internal states, and outputs. -Unfortunately, status quo programming techniques have no way of expressing this dependency graph directly. -Programmers must implicitly build this graph out of the correct sequencing of method calls and state updates. -In so doing, they throw away this valuable dependency information and the computer can no longer help us. -That is the root of the problem.

-
-
-
-

Behavior Graph

-
-

With Behavior Graph, we build our programs out of units of functionality called behaviors. -Behaviors manage state via components called resources. -Behaviors are simple, easily understood blocks of code paired with any relationships to these resources. -Resources are objects which encapsulate both state and how that state changes. -A behavior for our thermostat would be "when the user presses the Up or Down buttons, increase or decrease the desired temperature by one degree." -The desired temperature is the resource that this behavior manages.

-
-
-
-Login page -
-
-
-

An entire thermostat program would be built out of many of these behaviors. -So we add a second behavior, "when the current temperature is below the desired temperature, turn on the heating equipment." -Our behaviors will collaborate to implement the complete thermostat functionality without knowing about each other directly. -Instead, behaviors compose via resources, in this case desired temperature. -The first behavior declares that it is responsible for setting the desired temperature. -The second behavior declares that it uses the desired temperature to know if it needs to turn on the heat.

-
-
-
-Login page -
-
-
-

We never run behaviors directly by calling them like we do with methods. -Instead Behavior Graph uses the dependencies between behaviors and resources to determine which behaviors need to run and in which order. -If the user presses the Up button to raise the desired temperature above the current temperature, the heating behavior will automatically run after the temperature behavior updates the desired temperature resource.

-
-
-

Here we can see the contrast to the status quo approach of nesting chains of method calls. -In order to ensure the heat can be turned on when the up button is presset, the button press method needs to call the desired temperature setting method. -And that method in turn needs to call the heating equipment method. -Because no method runs unless another method calls it, we must explicitly weave these threads of control flow throughout our code. -In large programs, separately maintaining control flow to ensure our dependency graph is respected is both difficult and error prone.

-
-
-

Fred Brooks famously pointed out that software is necessarily complex because the problems themselves are complex. -With Behavior Graph we overcome our human complexity limits by delegating more of that work to the computer itself. -As programmers, we focus on individual behaviors and their immediate relationships. -The computer in turn handles the complex chore of sorting through hundreds or thousands of those behaviors to ensure a working program.

-
-
-

Behavior Graph gives us control flow for free.

-
-
-

Behavior Graph is a compact and mature library with no external dependencies. -It is used in production applications with millions of daily users. -It is available for multiple languages and platforms (Objective C/Swift, Typescript/Ja*vascript, Kotlin).

-
-
-
-
-
-

Walkthrough

-
-
-

We can illustrate how Behavior Graph code works in detail through another example application, a typical login screen.

-
-
-
-Login page -
-
-
-

As a first feature, we would like the Login button to remain disabled until the user has entered both a reasonable email and password. -If the user types in some password but an invalid email address (missing the '@' character, for example) the Login button will remain disabled. -Once she corrects the email address by adding an '@' character, the Login button should immediately enable.

-
-
-

In Behavior Graph, this unit of functionality constitutes a typical behavior. -It looks like this

-
-
-
-
1
-2
-3
-4
-5
-6
-7
-8
-
makeBehavior([email, password], [loginEnabled], (extent) => {
-
-    const emailValid = validEmailAddress(email.value);
-    const passwordValid = password.value.length > 0;
-    const enabled = emailValid && passwordValid;
-    loginEnabled.update(enabled);
-
-});
-
-
-
-
-

Behaviors have dependencies on units of information called resources. -This behavior depends on two resources, email and password. -They appear as a list in the first parameter to makeBehavior. -This list is called the behavior’s demands. -Our behavior has read only access to these resources.

-
-
-

As stated before, behaviors are never called directly. -In specifying a behavior’s demands, we are saying, "whenever any of these resources updates (changes), then this behavior needs to run". -In our example, when either email or password (or both) update, this behavior will run in response.

-
-
-

email and password are a specific type of resource called a state resource which is designed for saving and retreiving information. -The contents of these state resources is available via their value property.

-
-
-

The block of code specified in the behavior is the code that will run. -A typical behavior uses normal code to perform its work. -Here we check the validity of the email with a normal function. -We determine if the Login button should be enabled using normal boolean logic.

-
-
-

This behavior is responsible for the enabled state of the Login button. -This information is stored in another state resource called loginEnabled. -We specify a behavior’s responsibilites as a list in the second parameter to makeBehavior. -This list is called the behavior’s supplies. -A behavior can read and write the contents of its supplies. -The contents of a state resource can be written to by calling its update method.

-
-
-

We can continue to develop our Login page by adding a second feature. -When the user clicks the Login button and we are not already logging in, then we would like to enter into a logging in state. -In order to prevent mistakes, when we are in a logging in state, we would also like the Login button to be disabled.

-
-
-

To implement this new feature we introduce a second behavior and make a small change to our existing behavior.

-
-
-
-
 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
-10
-11
-12
-13
-14
-
makeBehavior([loginClick], [loggingIn], (extent) => {
-    if (loginClick.justUpdated && !loggingIn.value) {
-        loggingIn.update(true);
-    }
-});
-
-makeBehavior([email, password, loggingIn], [loginEnabled], (extent) => {
-
-    const emailValid = validEmailAddress(email.value);
-    const passwordValid = password.value.length > 0;
-    const enabled = emailValid && passwordValid & !loggingIn.value;
-    loginEnabled.update(enabled);
-
-});
-
-
-
-
-

The new behavior has one demand, loginClick. -This is a second type of resource called a moment resource. -Moments are designed to track momentary happenings such as a button click or network call returning. -We can check if a moment has just happened by accessing its justUpdated property.

-
-
-

When the user clicks on the button, loginClick will update, and this new behavior will run. -It performs a simple boolean check to determine if the loggingIn state resource needs to update to true. -It is allowed to update this resource because loggingIn is part of its supplies.

-
-
-

We also modified our previous behavior to include loggingIn as one of its demands. -This means it will run when the loggingIn resource updates as well as have permission to access the boolean value of loggingIn. -Now the state of loginEnabled depends on all three pieces of information: email, password, and loggingIn.

-
-
-
-Login Behavior Graph -
-
-
-

Information comes into our system via actions. -A typical UI library will provide some type of callback or event system to capture user inputs. -In this example we will listen to a click handler to create a new action which updates the loginClick moment resource.

-
-
-
-
1
-2
-3
-4
-5
-
loginButton.onClick = () => {
-    action("login button clicked", () => {
-        loginClick.update();
-    });
-};
-
-
-
-
-

We would similarly connect email and password to their respective text fields.

-
-
-

Once the user has entered a valid email and password, the Login button will enable. -When the user subsequently clicks on the Login button, the behavior that supplies loggingIn will run. -It will update the loggingIn resource to true. -This in turn will cause the behavior that supplies loginEnabled behavior to run. -It will update the loginEnabled resource to false.

-
-
-

In order to perform real output to the UI library, we need to create a side effect.

-
-
-
-
 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
-10
-11
-12
-
makeBehavior([email, password, loggingIn], [loginEnabled], (extent) => {
-
-    const emailValid = validEmailAddress(email.value);
-    const passwordValid = password.value.length > 0;
-    const enabled = emailValid && passwordValid & !loggingIn.value;
-    loginEnabled.update(enabled);
-
-    extent.sideEffect("login button enabled", (extent) => {
-        loginButton.enabled = loginEnabled.value;
-    });
-
-});
-
-
-
-
-

Side effects are created directly inside behaviors. -This side effect updates the enabled state of the loginButton based on the state of the loginEnabled resource. -It does not run immediately, however. -Behavior Graph defers the running of side effects until after all behaviors have run. -Side effects are a practical way for Behavior Graph to create output while ensuring access to consistent state.

-
-
-

This example covers the primary concepts when developing with Behavior Graph. -There are, however, additional features that make Behavior Graph a practical software library. -The Programming Guide explains these features in detail.

-
-
-
-
-

Reactive Programming

-
-
-

Behavior Graph graph has many characteristics of a reactive programming library. -If you are familiar with other libraries in this family you should find some similarities. -There are some important distinctions:

-
-
-
    -
  • -

    Behaviors function as observers and resources function as observables. -They are always separate objects, however.

    -
  • -
  • -

    It is not based on streams.

    -
  • -
  • -

    It does not use a large library of functional combinators.

    -
  • -
  • -

    The principles are not programming language or platform specific.

    -
  • -
  • -

    It does not have glitches.

    -
  • -
  • -

    It does not permit cyclic dependencies and provides tools for discovering and avoiding them.

    -
  • -
  • -

    It is a dynamic dataflow graph. Relationships between behaviors and resources can change at runtime which enables powerful modeling techniques.

    -
  • -
-
-
-
-
- -
-
- -
-
-
-
- - - - \ No newline at end of file diff --git a/docs/typescript/js/deflate.js b/docs/typescript/js/deflate.js new file mode 100644 index 0000000..b452c84 --- /dev/null +++ b/docs/typescript/js/deflate.js @@ -0,0 +1,1652 @@ +/* Copyright (C) 1999 Masanao Izumo +* Version: 1.0.1 +* LastModified: Dec 25 1999 +*/ + +/* Interface: +* data = deflate(src); +*/ +const deflate = (function () { + /* constant parameters */ + var zip_WSIZE = 32768; // Sliding Window size + var zip_STORED_BLOCK = 0; + var zip_STATIC_TREES = 1; + var zip_DYN_TREES = 2; + + /* for deflate */ + var zip_DEFAULT_LEVEL = 6; + var zip_FULL_SEARCH = true; + var zip_INBUFSIZ = 32768; // Input buffer size + var zip_INBUF_EXTRA = 64; // Extra buffer + var zip_OUTBUFSIZ = 1024 * 8; + var zip_window_size = 2 * zip_WSIZE; + var zip_MIN_MATCH = 3; + var zip_MAX_MATCH = 258; + var zip_BITS = 16; + // for SMALL_MEM + var zip_LIT_BUFSIZE = 0x2000; + var zip_HASH_BITS = 13; + // for MEDIUM_MEM + // var zip_LIT_BUFSIZE = 0x4000; + // var zip_HASH_BITS = 14; + // for BIG_MEM + // var zip_LIT_BUFSIZE = 0x8000; + // var zip_HASH_BITS = 15; + //if(zip_LIT_BUFSIZE > zip_INBUFSIZ) + // alert("error: zip_INBUFSIZ is too small"); + //if((zip_WSIZE<<1) > (1< zip_BITS-1) + // alert("error: zip_HASH_BITS is too large"); + //if(zip_HASH_BITS < 8 || zip_MAX_MATCH != 258) + // alert("error: Code too clever"); + var zip_DIST_BUFSIZE = zip_LIT_BUFSIZE; + var zip_HASH_SIZE = 1 << zip_HASH_BITS; + var zip_HASH_MASK = zip_HASH_SIZE - 1; + var zip_WMASK = zip_WSIZE - 1; + var zip_NIL = 0; // Tail of hash chains + var zip_TOO_FAR = 4096; + var zip_MIN_LOOKAHEAD = zip_MAX_MATCH + zip_MIN_MATCH + 1; + var zip_MAX_DIST = zip_WSIZE - zip_MIN_LOOKAHEAD; + var zip_SMALLEST = 1; + var zip_MAX_BITS = 15; + var zip_MAX_BL_BITS = 7; + var zip_LENGTH_CODES = 29; + var zip_LITERALS = 256; + var zip_END_BLOCK = 256; + var zip_L_CODES = zip_LITERALS + 1 + zip_LENGTH_CODES; + var zip_D_CODES = 30; + var zip_BL_CODES = 19; + var zip_REP_3_6 = 16; + var zip_REPZ_3_10 = 17; + var zip_REPZ_11_138 = 18; + var zip_HEAP_SIZE = 2 * zip_L_CODES + 1; + var zip_H_SHIFT = parseInt((zip_HASH_BITS + zip_MIN_MATCH - 1) / + zip_MIN_MATCH); + + /* variables */ + var zip_free_queue; + var zip_qhead, zip_qtail; + var zip_initflag; + var zip_outbuf = null; + var zip_outcnt, zip_outoff; + var zip_complete; + var zip_window; + var zip_d_buf; + var zip_l_buf; + var zip_prev; + var zip_bi_buf; + var zip_bi_valid; + var zip_block_start; + var zip_ins_h; + var zip_hash_head; + var zip_prev_match; + var zip_match_available; + var zip_match_length; + var zip_prev_length; + var zip_strstart; + var zip_match_start; + var zip_eofile; + var zip_lookahead; + var zip_max_chain_length; + var zip_max_lazy_match; + var zip_compr_level; + var zip_good_match; + var zip_nice_match; + var zip_dyn_ltree; + var zip_dyn_dtree; + var zip_static_ltree; + var zip_static_dtree; + var zip_bl_tree; + var zip_l_desc; + var zip_d_desc; + var zip_bl_desc; + var zip_bl_count; + var zip_heap; + var zip_heap_len; + var zip_heap_max; + var zip_depth; + var zip_length_code; + var zip_dist_code; + var zip_base_length; + var zip_base_dist; + var zip_flag_buf; + var zip_last_lit; + var zip_last_dist; + var zip_last_flags; + var zip_flags; + var zip_flag_bit; + var zip_opt_len; + var zip_static_len; + var zip_deflate_data; + var zip_deflate_pos; + + /* objects (deflate) */ + + function zip_DeflateCT() { + this.fc = 0; // frequency count or bit string + this.dl = 0; // father node in Huffman tree or length of bit string + } + + function zip_DeflateTreeDesc() { + this.dyn_tree = null; // the dynamic tree + this.static_tree = null; // corresponding static tree or NULL + this.extra_bits = null; // extra bits for each code or NULL + this.extra_base = 0; // base index for extra_bits + this.elems = 0; // max number of elements in the tree + this.max_length = 0; // max bit length for the codes + this.max_code = 0; // largest code with non zero frequency + } + + /* Values for max_lazy_match, good_match and max_chain_length, depending on + * the desired pack level (0..9). The values given below have been tuned to + * exclude worst case performance for pathological files. Better values may be + * found for specific files. + */ + function zip_DeflateConfiguration(a, b, c, d) { + this.good_length = a; // reduce lazy search above this match length + this.max_lazy = b; // do not perform lazy search above this match length + this.nice_length = c; // quit search above this match length + this.max_chain = d; + } + + function zip_DeflateBuffer() { + this.next = null; + this.len = 0; + this.ptr = new Array(zip_OUTBUFSIZ); + this.off = 0; + } + + /* constant tables */ + var zip_extra_lbits = [ + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0]; + var zip_extra_dbits = [ + 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13]; + var zip_extra_blbits = [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 3, 7]; + var zip_bl_order = [16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15]; + var zip_configuration_table = [ + new zip_DeflateConfiguration(0, 0, 0, 0), + new zip_DeflateConfiguration(4, 4, 8, 4), + new zip_DeflateConfiguration(4, 5, 16, 8), + new zip_DeflateConfiguration(4, 6, 32, 32), + new zip_DeflateConfiguration(4, 4, 16, 16), + new zip_DeflateConfiguration(8, 16, 32, 32), + new zip_DeflateConfiguration(8, 16, 128, 128), + new zip_DeflateConfiguration(8, 32, 128, 256), + new zip_DeflateConfiguration(32, 128, 258, 1024), + new zip_DeflateConfiguration(32, 258, 258, 4096)]; + + + /* routines (deflate) */ + + function zip_deflate_start(level) { + var i; + + if (!level) + level = zip_DEFAULT_LEVEL; + else if (level < 1) + level = 1; + else if (level > 9) + level = 9; + + zip_compr_level = level; + zip_initflag = false; + zip_eofile = false; + if (zip_outbuf != null) + return; + + zip_free_queue = zip_qhead = zip_qtail = null; + zip_outbuf = new Array(zip_OUTBUFSIZ); + zip_window = new Array(zip_window_size); + zip_d_buf = new Array(zip_DIST_BUFSIZE); + zip_l_buf = new Array(zip_INBUFSIZ + zip_INBUF_EXTRA); + zip_prev = new Array(1 << zip_BITS); + zip_dyn_ltree = new Array(zip_HEAP_SIZE); + for (i = 0; i < zip_HEAP_SIZE; i++) + zip_dyn_ltree[i] = new zip_DeflateCT(); + zip_dyn_dtree = new Array(2 * zip_D_CODES + 1); + for (i = 0; i < 2 * zip_D_CODES + 1; i++) + zip_dyn_dtree[i] = new zip_DeflateCT(); + zip_static_ltree = new Array(zip_L_CODES + 2); + for (i = 0; i < zip_L_CODES + 2; i++) + zip_static_ltree[i] = new zip_DeflateCT(); + zip_static_dtree = new Array(zip_D_CODES); + for (i = 0; i < zip_D_CODES; i++) + zip_static_dtree[i] = new zip_DeflateCT(); + zip_bl_tree = new Array(2 * zip_BL_CODES + 1); + for (i = 0; i < 2 * zip_BL_CODES + 1; i++) + zip_bl_tree[i] = new zip_DeflateCT(); + zip_l_desc = new zip_DeflateTreeDesc(); + zip_d_desc = new zip_DeflateTreeDesc(); + zip_bl_desc = new zip_DeflateTreeDesc(); + zip_bl_count = new Array(zip_MAX_BITS + 1); + zip_heap = new Array(2 * zip_L_CODES + 1); + zip_depth = new Array(2 * zip_L_CODES + 1); + zip_length_code = new Array(zip_MAX_MATCH - zip_MIN_MATCH + 1); + zip_dist_code = new Array(512); + zip_base_length = new Array(zip_LENGTH_CODES); + zip_base_dist = new Array(zip_D_CODES); + zip_flag_buf = new Array(parseInt(zip_LIT_BUFSIZE / 8)); + } + + function zip_deflate_end() { + zip_free_queue = zip_qhead = zip_qtail = null; + zip_outbuf = null; + zip_window = null; + zip_d_buf = null; + zip_l_buf = null; + zip_prev = null; + zip_dyn_ltree = null; + zip_dyn_dtree = null; + zip_static_ltree = null; + zip_static_dtree = null; + zip_bl_tree = null; + zip_l_desc = null; + zip_d_desc = null; + zip_bl_desc = null; + zip_bl_count = null; + zip_heap = null; + zip_depth = null; + zip_length_code = null; + zip_dist_code = null; + zip_base_length = null; + zip_base_dist = null; + zip_flag_buf = null; + } + + function zip_reuse_queue(p) { + p.next = zip_free_queue; + zip_free_queue = p; + } + + function zip_new_queue() { + var p; + + if (zip_free_queue != null) { + p = zip_free_queue; + zip_free_queue = zip_free_queue.next; + } + else + p = new zip_DeflateBuffer(); + p.next = null; + p.len = p.off = 0; + + return p; + } + + function zip_head1(i) { + return zip_prev[zip_WSIZE + i]; + } + + function zip_head2(i, val) { + return zip_prev[zip_WSIZE + i] = val; + } + + /* put_byte is used for the compressed output, put_ubyte for the + * uncompressed output. However unlzw() uses window for its + * suffix table instead of its output buffer, so it does not use put_ubyte + * (to be cleaned up). + */ + function zip_put_byte(c) { + zip_outbuf[zip_outoff + zip_outcnt++] = c; + if (zip_outoff + zip_outcnt == zip_OUTBUFSIZ) + zip_qoutbuf(); + } + + /* Output a 16 bit value, lsb first */ + function zip_put_short(w) { + w &= 0xffff; + if (zip_outoff + zip_outcnt < zip_OUTBUFSIZ - 2) { + zip_outbuf[zip_outoff + zip_outcnt++] = (w & 0xff); + zip_outbuf[zip_outoff + zip_outcnt++] = (w >>> 8); + } else { + zip_put_byte(w & 0xff); + zip_put_byte(w >>> 8); + } + } + + /* ========================================================================== + * Insert string s in the dictionary and set match_head to the previous head + * of the hash chain (the most recent string with same hash key). Return + * the previous length of the hash chain. + * IN assertion: all calls to to INSERT_STRING are made with consecutive + * input characters and the first MIN_MATCH bytes of s are valid + * (except for the last MIN_MATCH-1 bytes of the input file). + */ + function zip_INSERT_STRING() { + zip_ins_h = ((zip_ins_h << zip_H_SHIFT) + ^ (zip_window[zip_strstart + zip_MIN_MATCH - 1] & 0xff)) + & zip_HASH_MASK; + zip_hash_head = zip_head1(zip_ins_h); + zip_prev[zip_strstart & zip_WMASK] = zip_hash_head; + zip_head2(zip_ins_h, zip_strstart); + } + + /* Send a code of the given tree. c and tree must not have side effects */ + function zip_SEND_CODE(c, tree) { + zip_send_bits(tree[c].fc, tree[c].dl); + } + + /* Mapping from a distance to a distance code. dist is the distance - 1 and + * must not have side effects. dist_code[256] and dist_code[257] are never + * used. + */ + function zip_D_CODE(dist) { + return (dist < 256 ? zip_dist_code[dist] + : zip_dist_code[256 + (dist >> 7)]) & 0xff; + } + + /* ========================================================================== + * Compares to subtrees, using the tree depth as tie breaker when + * the subtrees have equal frequency. This minimizes the worst case length. + */ + function zip_SMALLER(tree, n, m) { + return tree[n].fc < tree[m].fc || + (tree[n].fc == tree[m].fc && zip_depth[n] <= zip_depth[m]); + } + + /* ========================================================================== + * read string data + */ + function zip_read_buff(buff, offset, n) { + var i; + for (i = 0; i < n && zip_deflate_pos < zip_deflate_data.length; i++) + buff[offset + i] = + zip_deflate_data.charCodeAt(zip_deflate_pos++) & 0xff; + return i; + } + + /* ========================================================================== + * Initialize the "longest match" routines for a new file + */ + function zip_lm_init() { + var j; + + /* Initialize the hash table. */ + for (j = 0; j < zip_HASH_SIZE; j++) + // zip_head2(j, zip_NIL); + zip_prev[zip_WSIZE + j] = 0; + /* prev will be initialized on the fly */ + + /* Set the default configuration parameters: + */ + zip_max_lazy_match = zip_configuration_table[zip_compr_level].max_lazy; + zip_good_match = zip_configuration_table[zip_compr_level].good_length; + if (!zip_FULL_SEARCH) + zip_nice_match = zip_configuration_table[zip_compr_level].nice_length; + zip_max_chain_length = zip_configuration_table[zip_compr_level].max_chain; + + zip_strstart = 0; + zip_block_start = 0; + + zip_lookahead = zip_read_buff(zip_window, 0, 2 * zip_WSIZE); + if (zip_lookahead <= 0) { + zip_eofile = true; + zip_lookahead = 0; + return; + } + zip_eofile = false; + /* Make sure that we always have enough lookahead. This is important + * if input comes from a device such as a tty. + */ + while (zip_lookahead < zip_MIN_LOOKAHEAD && !zip_eofile) + zip_fill_window(); + + /* If lookahead < MIN_MATCH, ins_h is garbage, but this is + * not important since only literal bytes will be emitted. + */ + zip_ins_h = 0; + for (j = 0; j < zip_MIN_MATCH - 1; j++) { + // UPDATE_HASH(ins_h, window[j]); + zip_ins_h = ((zip_ins_h << zip_H_SHIFT) ^ (zip_window[j] & 0xff)) & zip_HASH_MASK; + } + } + + /* ========================================================================== + * Set match_start to the longest match starting at the given string and + * return its length. Matches shorter or equal to prev_length are discarded, + * in which case the result is equal to prev_length and match_start is + * garbage. + * IN assertions: cur_match is the head of the hash chain for the current + * string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1 + */ + function zip_longest_match(cur_match) { + var chain_length = zip_max_chain_length; // max hash chain length + var scanp = zip_strstart; // current string + var matchp; // matched string + var len; // length of current match + var best_len = zip_prev_length; // best match length so far + + /* Stop when cur_match becomes <= limit. To simplify the code, + * we prevent matches with the string of window index 0. + */ + var limit = (zip_strstart > zip_MAX_DIST ? zip_strstart - zip_MAX_DIST : zip_NIL); + + var strendp = zip_strstart + zip_MAX_MATCH; + var scan_end1 = zip_window[scanp + best_len - 1]; + var scan_end = zip_window[scanp + best_len]; + + /* Do not waste too much time if we already have a good match: */ + if (zip_prev_length >= zip_good_match) + chain_length >>= 2; + + // Assert(encoder->strstart <= window_size-MIN_LOOKAHEAD, "insufficient lookahead"); + + do { + // Assert(cur_match < encoder->strstart, "no future"); + matchp = cur_match; + + /* Skip to next match if the match length cannot increase + * or if the match length is less than 2: + */ + if (zip_window[matchp + best_len] != scan_end || + zip_window[matchp + best_len - 1] != scan_end1 || + zip_window[matchp] != zip_window[scanp] || + zip_window[++matchp] != zip_window[scanp + 1]) { + continue; + } + + /* The check at best_len-1 can be removed because it will be made + * again later. (This heuristic is not always a win.) + * It is not necessary to compare scan[2] and match[2] since they + * are always equal when the other bytes match, given that + * the hash keys are equal and that HASH_BITS >= 8. + */ + scanp += 2; + matchp++; + + /* We check for insufficient lookahead only every 8th comparison; + * the 256th check will be made at strstart+258. + */ + do { + } while (zip_window[++scanp] == zip_window[++matchp] && + zip_window[++scanp] == zip_window[++matchp] && + zip_window[++scanp] == zip_window[++matchp] && + zip_window[++scanp] == zip_window[++matchp] && + zip_window[++scanp] == zip_window[++matchp] && + zip_window[++scanp] == zip_window[++matchp] && + zip_window[++scanp] == zip_window[++matchp] && + zip_window[++scanp] == zip_window[++matchp] && + scanp < strendp); + + len = zip_MAX_MATCH - (strendp - scanp); + scanp = strendp - zip_MAX_MATCH; + + if (len > best_len) { + zip_match_start = cur_match; + best_len = len; + if (zip_FULL_SEARCH) { + if (len >= zip_MAX_MATCH) break; + } else { + if (len >= zip_nice_match) break; + } + + scan_end1 = zip_window[scanp + best_len - 1]; + scan_end = zip_window[scanp + best_len]; + } + } while ((cur_match = zip_prev[cur_match & zip_WMASK]) > limit + && --chain_length != 0); + + return best_len; + } + + /* ========================================================================== + * Fill the window when the lookahead becomes insufficient. + * Updates strstart and lookahead, and sets eofile if end of input file. + * IN assertion: lookahead < MIN_LOOKAHEAD && strstart + lookahead > 0 + * OUT assertions: at least one byte has been read, or eofile is set; + * file reads are performed for at least two bytes (required for the + * translate_eol option). + */ + function zip_fill_window() { + var n, m; + + // Amount of free space at the end of the window. + var more = zip_window_size - zip_lookahead - zip_strstart; + + /* If the window is almost full and there is insufficient lookahead, + * move the upper half to the lower one to make room in the upper half. + */ + if (more == -1) { + /* Very unlikely, but possible on 16 bit machine if strstart == 0 + * and lookahead == 1 (input done one byte at time) + */ + more--; + } else if (zip_strstart >= zip_WSIZE + zip_MAX_DIST) { + /* By the IN assertion, the window is not empty so we can't confuse + * more == 0 with more == 64K on a 16 bit machine. + */ + // Assert(window_size == (ulg)2*WSIZE, "no sliding with BIG_MEM"); + + // System.arraycopy(window, WSIZE, window, 0, WSIZE); + for (n = 0; n < zip_WSIZE; n++) + zip_window[n] = zip_window[n + zip_WSIZE]; + + zip_match_start -= zip_WSIZE; + zip_strstart -= zip_WSIZE; /* we now have strstart >= MAX_DIST: */ + zip_block_start -= zip_WSIZE; + + for (n = 0; n < zip_HASH_SIZE; n++) { + m = zip_head1(n); + zip_head2(n, m >= zip_WSIZE ? m - zip_WSIZE : zip_NIL); + } + for (n = 0; n < zip_WSIZE; n++) { + /* If n is not on any hash chain, prev[n] is garbage but + * its value will never be used. + */ + m = zip_prev[n]; + zip_prev[n] = (m >= zip_WSIZE ? m - zip_WSIZE : zip_NIL); + } + more += zip_WSIZE; + } + // At this point, more >= 2 + if (!zip_eofile) { + n = zip_read_buff(zip_window, zip_strstart + zip_lookahead, more); + if (n <= 0) + zip_eofile = true; + else + zip_lookahead += n; + } + } + + /* ========================================================================== + * Processes a new input file and return its compressed length. This + * function does not perform lazy evaluationof matches and inserts + * new strings in the dictionary only for unmatched strings or for short + * matches. It is used only for the fast compression options. + */ + function zip_deflate_fast() { + while (zip_lookahead != 0 && zip_qhead == null) { + var flush; // set if current block must be flushed + + /* Insert the string window[strstart .. strstart+2] in the + * dictionary, and set hash_head to the head of the hash chain: + */ + zip_INSERT_STRING(); + + /* Find the longest match, discarding those <= prev_length. + * At this point we have always match_length < MIN_MATCH + */ + if (zip_hash_head != zip_NIL && + zip_strstart - zip_hash_head <= zip_MAX_DIST) { + /* To simplify the code, we prevent matches with the string + * of window index 0 (in particular we have to avoid a match + * of the string with itself at the start of the input file). + */ + zip_match_length = zip_longest_match(zip_hash_head); + /* longest_match() sets match_start */ + if (zip_match_length > zip_lookahead) + zip_match_length = zip_lookahead; + } + if (zip_match_length >= zip_MIN_MATCH) { + // check_match(strstart, match_start, match_length); + + flush = zip_ct_tally(zip_strstart - zip_match_start, + zip_match_length - zip_MIN_MATCH); + zip_lookahead -= zip_match_length; + + /* Insert new strings in the hash table only if the match length + * is not too large. This saves time but degrades compression. + */ + if (zip_match_length <= zip_max_lazy_match) { + zip_match_length--; // string at strstart already in hash table + do { + zip_strstart++; + zip_INSERT_STRING(); + /* strstart never exceeds WSIZE-MAX_MATCH, so there are + * always MIN_MATCH bytes ahead. If lookahead < MIN_MATCH + * these bytes are garbage, but it does not matter since + * the next lookahead bytes will be emitted as literals. + */ + } while (--zip_match_length != 0); + zip_strstart++; + } else { + zip_strstart += zip_match_length; + zip_match_length = 0; + zip_ins_h = zip_window[zip_strstart] & 0xff; + // UPDATE_HASH(ins_h, window[strstart + 1]); + zip_ins_h = ((zip_ins_h << zip_H_SHIFT) ^ (zip_window[zip_strstart + 1] & 0xff)) & zip_HASH_MASK; + + //#if MIN_MATCH != 3 + // Call UPDATE_HASH() MIN_MATCH-3 more times + //#endif + + } + } else { + /* No match, output a literal byte */ + flush = zip_ct_tally(0, zip_window[zip_strstart] & 0xff); + zip_lookahead--; + zip_strstart++; + } + if (flush) { + zip_flush_block(0); + zip_block_start = zip_strstart; + } + + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need MAX_MATCH bytes + * for the next match, plus MIN_MATCH bytes to insert the + * string following the next match. + */ + while (zip_lookahead < zip_MIN_LOOKAHEAD && !zip_eofile) + zip_fill_window(); + } + } + + function zip_deflate_better() { + /* Process the input block. */ + while (zip_lookahead != 0 && zip_qhead == null) { + /* Insert the string window[strstart .. strstart+2] in the + * dictionary, and set hash_head to the head of the hash chain: + */ + zip_INSERT_STRING(); + + /* Find the longest match, discarding those <= prev_length. + */ + zip_prev_length = zip_match_length; + zip_prev_match = zip_match_start; + zip_match_length = zip_MIN_MATCH - 1; + + if (zip_hash_head != zip_NIL && + zip_prev_length < zip_max_lazy_match && + zip_strstart - zip_hash_head <= zip_MAX_DIST) { + /* To simplify the code, we prevent matches with the string + * of window index 0 (in particular we have to avoid a match + * of the string with itself at the start of the input file). + */ + zip_match_length = zip_longest_match(zip_hash_head); + /* longest_match() sets match_start */ + if (zip_match_length > zip_lookahead) + zip_match_length = zip_lookahead; + + /* Ignore a length 3 match if it is too distant: */ + if (zip_match_length == zip_MIN_MATCH && + zip_strstart - zip_match_start > zip_TOO_FAR) { + /* If prev_match is also MIN_MATCH, match_start is garbage + * but we will ignore the current match anyway. + */ + zip_match_length--; + } + } + /* If there was a match at the previous step and the current + * match is not better, output the previous match: + */ + if (zip_prev_length >= zip_MIN_MATCH && + zip_match_length <= zip_prev_length) { + var flush; // set if current block must be flushed + + // check_match(strstart - 1, prev_match, prev_length); + flush = zip_ct_tally(zip_strstart - 1 - zip_prev_match, + zip_prev_length - zip_MIN_MATCH); + + /* Insert in hash table all strings up to the end of the match. + * strstart-1 and strstart are already inserted. + */ + zip_lookahead -= zip_prev_length - 1; + zip_prev_length -= 2; + do { + zip_strstart++; + zip_INSERT_STRING(); + /* strstart never exceeds WSIZE-MAX_MATCH, so there are + * always MIN_MATCH bytes ahead. If lookahead < MIN_MATCH + * these bytes are garbage, but it does not matter since the + * next lookahead bytes will always be emitted as literals. + */ + } while (--zip_prev_length != 0); + zip_match_available = 0; + zip_match_length = zip_MIN_MATCH - 1; + zip_strstart++; + if (flush) { + zip_flush_block(0); + zip_block_start = zip_strstart; + } + } else if (zip_match_available != 0) { + /* If there was no match at the previous position, output a + * single literal. If there was a match but the current match + * is longer, truncate the previous match to a single literal. + */ + if (zip_ct_tally(0, zip_window[zip_strstart - 1] & 0xff)) { + zip_flush_block(0); + zip_block_start = zip_strstart; + } + zip_strstart++; + zip_lookahead--; + } else { + /* There is no previous match to compare with, wait for + * the next step to decide. + */ + zip_match_available = 1; + zip_strstart++; + zip_lookahead--; + } + + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need MAX_MATCH bytes + * for the next match, plus MIN_MATCH bytes to insert the + * string following the next match. + */ + while (zip_lookahead < zip_MIN_LOOKAHEAD && !zip_eofile) + zip_fill_window(); + } + } + + function zip_init_deflate() { + if (zip_eofile) + return; + zip_bi_buf = 0; + zip_bi_valid = 0; + zip_ct_init(); + zip_lm_init(); + + zip_qhead = null; + zip_outcnt = 0; + zip_outoff = 0; + + if (zip_compr_level <= 3) { + zip_prev_length = zip_MIN_MATCH - 1; + zip_match_length = 0; + } + else { + zip_match_length = zip_MIN_MATCH - 1; + zip_match_available = 0; + } + + zip_complete = false; + } + + /* ========================================================================== + * Same as above, but achieves better compression. We use a lazy + * evaluation for matches: a match is finally adopted only if there is + * no better match at the next window position. + */ + function zip_deflate_internal(buff, off, buff_size) { + var n; + + if (!zip_initflag) { + zip_init_deflate(); + zip_initflag = true; + if (zip_lookahead == 0) { // empty + zip_complete = true; + return 0; + } + } + + if ((n = zip_qcopy(buff, off, buff_size)) == buff_size) + return buff_size; + + if (zip_complete) + return n; + + if (zip_compr_level <= 3) // optimized for speed + zip_deflate_fast(); + else + zip_deflate_better(); + if (zip_lookahead == 0) { + if (zip_match_available != 0) + zip_ct_tally(0, zip_window[zip_strstart - 1] & 0xff); + zip_flush_block(1); + zip_complete = true; + } + return n + zip_qcopy(buff, n + off, buff_size - n); + } + + function zip_qcopy(buff, off, buff_size) { + var n, i, j; + + n = 0; + while (zip_qhead != null && n < buff_size) { + i = buff_size - n; + if (i > zip_qhead.len) + i = zip_qhead.len; + // System.arraycopy(qhead.ptr, qhead.off, buff, off + n, i); + for (j = 0; j < i; j++) + buff[off + n + j] = zip_qhead.ptr[zip_qhead.off + j]; + + zip_qhead.off += i; + zip_qhead.len -= i; + n += i; + if (zip_qhead.len == 0) { + var p; + p = zip_qhead; + zip_qhead = zip_qhead.next; + zip_reuse_queue(p); + } + } + + if (n == buff_size) + return n; + + if (zip_outoff < zip_outcnt) { + i = buff_size - n; + if (i > zip_outcnt - zip_outoff) + i = zip_outcnt - zip_outoff; + // System.arraycopy(outbuf, outoff, buff, off + n, i); + for (j = 0; j < i; j++) + buff[off + n + j] = zip_outbuf[zip_outoff + j]; + zip_outoff += i; + n += i; + if (zip_outcnt == zip_outoff) + zip_outcnt = zip_outoff = 0; + } + return n; + } + + /* ========================================================================== + * Allocate the match buffer, initialize the various tables and save the + * location of the internal file attribute (ascii/binary) and method + * (DEFLATE/STORE). + */ + function zip_ct_init() { + var n; // iterates over tree elements + var bits; // bit counter + var length; // length value + var code; // code value + var dist; // distance index + + if (zip_static_dtree[0].dl != 0) return; // ct_init already called + + zip_l_desc.dyn_tree = zip_dyn_ltree; + zip_l_desc.static_tree = zip_static_ltree; + zip_l_desc.extra_bits = zip_extra_lbits; + zip_l_desc.extra_base = zip_LITERALS + 1; + zip_l_desc.elems = zip_L_CODES; + zip_l_desc.max_length = zip_MAX_BITS; + zip_l_desc.max_code = 0; + + zip_d_desc.dyn_tree = zip_dyn_dtree; + zip_d_desc.static_tree = zip_static_dtree; + zip_d_desc.extra_bits = zip_extra_dbits; + zip_d_desc.extra_base = 0; + zip_d_desc.elems = zip_D_CODES; + zip_d_desc.max_length = zip_MAX_BITS; + zip_d_desc.max_code = 0; + + zip_bl_desc.dyn_tree = zip_bl_tree; + zip_bl_desc.static_tree = null; + zip_bl_desc.extra_bits = zip_extra_blbits; + zip_bl_desc.extra_base = 0; + zip_bl_desc.elems = zip_BL_CODES; + zip_bl_desc.max_length = zip_MAX_BL_BITS; + zip_bl_desc.max_code = 0; + + // Initialize the mapping length (0..255) -> length code (0..28) + length = 0; + for (code = 0; code < zip_LENGTH_CODES - 1; code++) { + zip_base_length[code] = length; + for (n = 0; n < (1 << zip_extra_lbits[code]); n++) + zip_length_code[length++] = code; + } + // Assert (length == 256, "ct_init: length != 256"); + + /* Note that the length 255 (match length 258) can be represented + * in two different ways: code 284 + 5 bits or code 285, so we + * overwrite length_code[255] to use the best encoding: + */ + zip_length_code[length - 1] = code; + + /* Initialize the mapping dist (0..32K) -> dist code (0..29) */ + dist = 0; + for (code = 0; code < 16; code++) { + zip_base_dist[code] = dist; + for (n = 0; n < (1 << zip_extra_dbits[code]); n++) { + zip_dist_code[dist++] = code; + } + } + // Assert (dist == 256, "ct_init: dist != 256"); + dist >>= 7; // from now on, all distances are divided by 128 + for (; code < zip_D_CODES; code++) { + zip_base_dist[code] = dist << 7; + for (n = 0; n < (1 << (zip_extra_dbits[code] - 7)); n++) + zip_dist_code[256 + dist++] = code; + } + // Assert (dist == 256, "ct_init: 256+dist != 512"); + + // Construct the codes of the static literal tree + for (bits = 0; bits <= zip_MAX_BITS; bits++) + zip_bl_count[bits] = 0; + n = 0; + while (n <= 143) { zip_static_ltree[n++].dl = 8; zip_bl_count[8]++; } + while (n <= 255) { zip_static_ltree[n++].dl = 9; zip_bl_count[9]++; } + while (n <= 279) { zip_static_ltree[n++].dl = 7; zip_bl_count[7]++; } + while (n <= 287) { zip_static_ltree[n++].dl = 8; zip_bl_count[8]++; } + /* Codes 286 and 287 do not exist, but we must include them in the + * tree construction to get a canonical Huffman tree (longest code + * all ones) + */ + zip_gen_codes(zip_static_ltree, zip_L_CODES + 1); + + /* The static distance tree is trivial: */ + for (n = 0; n < zip_D_CODES; n++) { + zip_static_dtree[n].dl = 5; + zip_static_dtree[n].fc = zip_bi_reverse(n, 5); + } + + // Initialize the first block of the first file: + zip_init_block(); + } + + /* ========================================================================== + * Initialize a new block. + */ + function zip_init_block() { + var n; // iterates over tree elements + + // Initialize the trees. + for (n = 0; n < zip_L_CODES; n++) zip_dyn_ltree[n].fc = 0; + for (n = 0; n < zip_D_CODES; n++) zip_dyn_dtree[n].fc = 0; + for (n = 0; n < zip_BL_CODES; n++) zip_bl_tree[n].fc = 0; + + zip_dyn_ltree[zip_END_BLOCK].fc = 1; + zip_opt_len = zip_static_len = 0; + zip_last_lit = zip_last_dist = zip_last_flags = 0; + zip_flags = 0; + zip_flag_bit = 1; + } + + /* ========================================================================== + * Restore the heap property by moving down the tree starting at node k, + * exchanging a node with the smallest of its two sons if necessary, stopping + * when the heap property is re-established (each father smaller than its + * two sons). + */ + function zip_pqdownheap( + tree, // the tree to restore + k) { // node to move down + var v = zip_heap[k]; + var j = k << 1; // left son of k + + while (j <= zip_heap_len) { + // Set j to the smallest of the two sons: + if (j < zip_heap_len && + zip_SMALLER(tree, zip_heap[j + 1], zip_heap[j])) + j++; + + // Exit if v is smaller than both sons + if (zip_SMALLER(tree, v, zip_heap[j])) + break; + + // Exchange v with the smallest son + zip_heap[k] = zip_heap[j]; + k = j; + + // And continue down the tree, setting j to the left son of k + j <<= 1; + } + zip_heap[k] = v; + } + + /* ========================================================================== + * Compute the optimal bit lengths for a tree and update the total bit length + * for the current block. + * IN assertion: the fields freq and dad are set, heap[heap_max] and + * above are the tree nodes sorted by increasing frequency. + * OUT assertions: the field len is set to the optimal bit length, the + * array bl_count contains the frequencies for each bit length. + * The length opt_len is updated; static_len is also updated if stree is + * not null. + */ + function zip_gen_bitlen(desc) { // the tree descriptor + var tree = desc.dyn_tree; + var extra = desc.extra_bits; + var base = desc.extra_base; + var max_code = desc.max_code; + var max_length = desc.max_length; + var stree = desc.static_tree; + var h; // heap index + var n, m; // iterate over the tree elements + var bits; // bit length + var xbits; // extra bits + var f; // frequency + var overflow = 0; // number of elements with bit length too large + + for (bits = 0; bits <= zip_MAX_BITS; bits++) + zip_bl_count[bits] = 0; + + /* In a first pass, compute the optimal bit lengths (which may + * overflow in the case of the bit length tree). + */ + tree[zip_heap[zip_heap_max]].dl = 0; // root of the heap + + for (h = zip_heap_max + 1; h < zip_HEAP_SIZE; h++) { + n = zip_heap[h]; + bits = tree[tree[n].dl].dl + 1; + if (bits > max_length) { + bits = max_length; + overflow++; + } + tree[n].dl = bits; + // We overwrite tree[n].dl which is no longer needed + + if (n > max_code) + continue; // not a leaf node + + zip_bl_count[bits]++; + xbits = 0; + if (n >= base) + xbits = extra[n - base]; + f = tree[n].fc; + zip_opt_len += f * (bits + xbits); + if (stree != null) + zip_static_len += f * (stree[n].dl + xbits); + } + if (overflow == 0) + return; + + // This happens for example on obj2 and pic of the Calgary corpus + + // Find the first bit length which could increase: + do { + bits = max_length - 1; + while (zip_bl_count[bits] == 0) + bits--; + zip_bl_count[bits]--; // move one leaf down the tree + zip_bl_count[bits + 1] += 2; // move one overflow item as its brother + zip_bl_count[max_length]--; + /* The brother of the overflow item also moves one step up, + * but this does not affect bl_count[max_length] + */ + overflow -= 2; + } while (overflow > 0); + + /* Now recompute all bit lengths, scanning in increasing frequency. + * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all + * lengths instead of fixing only the wrong ones. This idea is taken + * from 'ar' written by Haruhiko Okumura.) + */ + for (bits = max_length; bits != 0; bits--) { + n = zip_bl_count[bits]; + while (n != 0) { + m = zip_heap[--h]; + if (m > max_code) + continue; + if (tree[m].dl != bits) { + zip_opt_len += (bits - tree[m].dl) * tree[m].fc; + tree[m].fc = bits; + } + n--; + } + } + } + + /* ========================================================================== + * Generate the codes for a given tree and bit counts (which need not be + * optimal). + * IN assertion: the array bl_count contains the bit length statistics for + * the given tree and the field len is set for all tree elements. + * OUT assertion: the field code is set for all tree elements of non + * zero code length. + */ + function zip_gen_codes(tree, // the tree to decorate + max_code) { // largest code with non zero frequency + var next_code = new Array(zip_MAX_BITS + 1); // next code value for each bit length + var code = 0; // running code value + var bits; // bit index + var n; // code index + + /* The distribution counts are first used to generate the code values + * without bit reversal. + */ + for (bits = 1; bits <= zip_MAX_BITS; bits++) { + code = ((code + zip_bl_count[bits - 1]) << 1); + next_code[bits] = code; + } + + /* Check that the bit counts in bl_count are consistent. The last code + * must be all ones. + */ + // Assert (code + encoder->bl_count[MAX_BITS]-1 == (1<> 1; n >= 1; n--) + zip_pqdownheap(tree, n); + + /* Construct the Huffman tree by repeatedly combining the least two + * frequent nodes. + */ + do { + n = zip_heap[zip_SMALLEST]; + zip_heap[zip_SMALLEST] = zip_heap[zip_heap_len--]; + zip_pqdownheap(tree, zip_SMALLEST); + + m = zip_heap[zip_SMALLEST]; // m = node of next least frequency + + // keep the nodes sorted by frequency + zip_heap[--zip_heap_max] = n; + zip_heap[--zip_heap_max] = m; + + // Create a new node father of n and m + tree[node].fc = tree[n].fc + tree[m].fc; + // depth[node] = (char)(MAX(depth[n], depth[m]) + 1); + if (zip_depth[n] > zip_depth[m] + 1) + zip_depth[node] = zip_depth[n]; + else + zip_depth[node] = zip_depth[m] + 1; + tree[n].dl = tree[m].dl = node; + + // and insert the new node in the heap + zip_heap[zip_SMALLEST] = node++; + zip_pqdownheap(tree, zip_SMALLEST); + + } while (zip_heap_len >= 2); + + zip_heap[--zip_heap_max] = zip_heap[zip_SMALLEST]; + + /* At this point, the fields freq and dad are set. We can now + * generate the bit lengths. + */ + zip_gen_bitlen(desc); + + // The field len is now set, we can generate the bit codes + zip_gen_codes(tree, max_code); + } + + /* ========================================================================== + * Scan a literal or distance tree to determine the frequencies of the codes + * in the bit length tree. Updates opt_len to take into account the repeat + * counts. (The contribution of the bit length codes will be added later + * during the construction of bl_tree.) + */ + function zip_scan_tree(tree,// the tree to be scanned + max_code) { // and its largest code of non zero frequency + var n; // iterates over all tree elements + var prevlen = -1; // last emitted length + var curlen; // length of current code + var nextlen = tree[0].dl; // length of next code + var count = 0; // repeat count of the current code + var max_count = 7; // max repeat count + var min_count = 4; // min repeat count + + if (nextlen == 0) { + max_count = 138; + min_count = 3; + } + tree[max_code + 1].dl = 0xffff; // guard + + for (n = 0; n <= max_code; n++) { + curlen = nextlen; + nextlen = tree[n + 1].dl; + if (++count < max_count && curlen == nextlen) + continue; + else if (count < min_count) + zip_bl_tree[curlen].fc += count; + else if (curlen != 0) { + if (curlen != prevlen) + zip_bl_tree[curlen].fc++; + zip_bl_tree[zip_REP_3_6].fc++; + } else if (count <= 10) + zip_bl_tree[zip_REPZ_3_10].fc++; + else + zip_bl_tree[zip_REPZ_11_138].fc++; + count = 0; prevlen = curlen; + if (nextlen == 0) { + max_count = 138; + min_count = 3; + } else if (curlen == nextlen) { + max_count = 6; + min_count = 3; + } else { + max_count = 7; + min_count = 4; + } + } + } + + /* ========================================================================== + * Send a literal or distance tree in compressed form, using the codes in + * bl_tree. + */ + function zip_send_tree(tree, // the tree to be scanned + max_code) { // and its largest code of non zero frequency + var n; // iterates over all tree elements + var prevlen = -1; // last emitted length + var curlen; // length of current code + var nextlen = tree[0].dl; // length of next code + var count = 0; // repeat count of the current code + var max_count = 7; // max repeat count + var min_count = 4; // min repeat count + + /* tree[max_code+1].dl = -1; */ /* guard already set */ + if (nextlen == 0) { + max_count = 138; + min_count = 3; + } + + for (n = 0; n <= max_code; n++) { + curlen = nextlen; + nextlen = tree[n + 1].dl; + if (++count < max_count && curlen == nextlen) { + continue; + } else if (count < min_count) { + do { zip_SEND_CODE(curlen, zip_bl_tree); } while (--count != 0); + } else if (curlen != 0) { + if (curlen != prevlen) { + zip_SEND_CODE(curlen, zip_bl_tree); + count--; + } + // Assert(count >= 3 && count <= 6, " 3_6?"); + zip_SEND_CODE(zip_REP_3_6, zip_bl_tree); + zip_send_bits(count - 3, 2); + } else if (count <= 10) { + zip_SEND_CODE(zip_REPZ_3_10, zip_bl_tree); + zip_send_bits(count - 3, 3); + } else { + zip_SEND_CODE(zip_REPZ_11_138, zip_bl_tree); + zip_send_bits(count - 11, 7); + } + count = 0; + prevlen = curlen; + if (nextlen == 0) { + max_count = 138; + min_count = 3; + } else if (curlen == nextlen) { + max_count = 6; + min_count = 3; + } else { + max_count = 7; + min_count = 4; + } + } + } + + /* ========================================================================== + * Construct the Huffman tree for the bit lengths and return the index in + * bl_order of the last bit length code to send. + */ + function zip_build_bl_tree() { + var max_blindex; // index of last bit length code of non zero freq + + // Determine the bit length frequencies for literal and distance trees + zip_scan_tree(zip_dyn_ltree, zip_l_desc.max_code); + zip_scan_tree(zip_dyn_dtree, zip_d_desc.max_code); + + // Build the bit length tree: + zip_build_tree(zip_bl_desc); + /* opt_len now includes the length of the tree representations, except + * the lengths of the bit lengths codes and the 5+5+4 bits for the counts. + */ + + /* Determine the number of bit length codes to send. The pkzip format + * requires that at least 4 bit length codes be sent. (appnote.txt says + * 3 but the actual value used is 4.) + */ + for (max_blindex = zip_BL_CODES - 1; max_blindex >= 3; max_blindex--) { + if (zip_bl_tree[zip_bl_order[max_blindex]].dl != 0) break; + } + /* Update opt_len to include the bit length tree and counts */ + zip_opt_len += 3 * (max_blindex + 1) + 5 + 5 + 4; + // Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld", + // encoder->opt_len, encoder->static_len)); + + return max_blindex; + } + + /* ========================================================================== + * Send the header for a block using dynamic Huffman trees: the counts, the + * lengths of the bit length codes, the literal tree and the distance tree. + * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4. + */ + function zip_send_all_trees(lcodes, dcodes, blcodes) { // number of codes for each tree + var rank; // index in bl_order + + // Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes"); + // Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES, + // "too many codes"); + // Tracev((stderr, "\nbl counts: ")); + zip_send_bits(lcodes - 257, 5); // not +255 as stated in appnote.txt + zip_send_bits(dcodes - 1, 5); + zip_send_bits(blcodes - 4, 4); // not -3 as stated in appnote.txt + for (rank = 0; rank < blcodes; rank++) { + // Tracev((stderr, "\nbl code %2d ", bl_order[rank])); + zip_send_bits(zip_bl_tree[zip_bl_order[rank]].dl, 3); + } + + // send the literal tree + zip_send_tree(zip_dyn_ltree, lcodes - 1); + + // send the distance tree + zip_send_tree(zip_dyn_dtree, dcodes - 1); + } + + /* ========================================================================== + * Determine the best encoding for the current block: dynamic trees, static + * trees or store, and output the encoded block to the zip file. + */ + function zip_flush_block(eof) { // true if this is the last block for a file + var opt_lenb, static_lenb; // opt_len and static_len in bytes + var max_blindex; // index of last bit length code of non zero freq + var stored_len; // length of input block + + stored_len = zip_strstart - zip_block_start; + zip_flag_buf[zip_last_flags] = zip_flags; // Save the flags for the last 8 items + + // Construct the literal and distance trees + zip_build_tree(zip_l_desc); + // Tracev((stderr, "\nlit data: dyn %ld, stat %ld", + // encoder->opt_len, encoder->static_len)); + + zip_build_tree(zip_d_desc); + // Tracev((stderr, "\ndist data: dyn %ld, stat %ld", + // encoder->opt_len, encoder->static_len)); + /* At this point, opt_len and static_len are the total bit lengths of + * the compressed block data, excluding the tree representations. + */ + + /* Build the bit length tree for the above two trees, and get the index + * in bl_order of the last bit length code to send. + */ + max_blindex = zip_build_bl_tree(); + + // Determine the best encoding. Compute first the block length in bytes + opt_lenb = (zip_opt_len + 3 + 7) >> 3; + static_lenb = (zip_static_len + 3 + 7) >> 3; + + // Trace((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u dist %u ", + // opt_lenb, encoder->opt_len, + // static_lenb, encoder->static_len, stored_len, + // encoder->last_lit, encoder->last_dist)); + + if (static_lenb <= opt_lenb) + opt_lenb = static_lenb; + if (stored_len + 4 <= opt_lenb // 4: two words for the lengths + && zip_block_start >= 0) { + var i; + + /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE. + * Otherwise we can't have processed more than WSIZE input bytes since + * the last block flush, because compression would have been + * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to + * transform a block into a stored block. + */ + zip_send_bits((zip_STORED_BLOCK << 1) + eof, 3); /* send block type */ + zip_bi_windup(); /* align on byte boundary */ + zip_put_short(stored_len); + zip_put_short(~stored_len); + + // copy block + /* + p = &window[block_start]; + for(i = 0; i < stored_len; i++) + put_byte(p[i]); + */ + for (i = 0; i < stored_len; i++) + zip_put_byte(zip_window[zip_block_start + i]); + + } else if (static_lenb == opt_lenb) { + zip_send_bits((zip_STATIC_TREES << 1) + eof, 3); + zip_compress_block(zip_static_ltree, zip_static_dtree); + } else { + zip_send_bits((zip_DYN_TREES << 1) + eof, 3); + zip_send_all_trees(zip_l_desc.max_code + 1, + zip_d_desc.max_code + 1, + max_blindex + 1); + zip_compress_block(zip_dyn_ltree, zip_dyn_dtree); + } + + zip_init_block(); + + if (eof != 0) + zip_bi_windup(); + } + + /* ========================================================================== + * Save the match info and tally the frequency counts. Return true if + * the current block must be flushed. + */ + function zip_ct_tally( + dist, // distance of matched string + lc) { // match length-MIN_MATCH or unmatched char (if dist==0) + zip_l_buf[zip_last_lit++] = lc; + if (dist == 0) { + // lc is the unmatched char + zip_dyn_ltree[lc].fc++; + } else { + // Here, lc is the match length - MIN_MATCH + dist--; // dist = match distance - 1 + // Assert((ush)dist < (ush)MAX_DIST && + // (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) && + // (ush)D_CODE(dist) < (ush)D_CODES, "ct_tally: bad match"); + + zip_dyn_ltree[zip_length_code[lc] + zip_LITERALS + 1].fc++; + zip_dyn_dtree[zip_D_CODE(dist)].fc++; + + zip_d_buf[zip_last_dist++] = dist; + zip_flags |= zip_flag_bit; + } + zip_flag_bit <<= 1; + + // Output the flags if they fill a byte + if ((zip_last_lit & 7) == 0) { + zip_flag_buf[zip_last_flags++] = zip_flags; + zip_flags = 0; + zip_flag_bit = 1; + } + // Try to guess if it is profitable to stop the current block here + if (zip_compr_level > 2 && (zip_last_lit & 0xfff) == 0) { + // Compute an upper bound for the compressed length + var out_length = zip_last_lit * 8; + var in_length = zip_strstart - zip_block_start; + var dcode; + + for (dcode = 0; dcode < zip_D_CODES; dcode++) { + out_length += zip_dyn_dtree[dcode].fc * (5 + zip_extra_dbits[dcode]); + } + out_length >>= 3; + // Trace((stderr,"\nlast_lit %u, last_dist %u, in %ld, out ~%ld(%ld%%) ", + // encoder->last_lit, encoder->last_dist, in_length, out_length, + // 100L - out_length*100L/in_length)); + if (zip_last_dist < parseInt(zip_last_lit / 2) && + out_length < parseInt(in_length / 2)) + return true; + } + return (zip_last_lit == zip_LIT_BUFSIZE - 1 || + zip_last_dist == zip_DIST_BUFSIZE); + /* We avoid equality with LIT_BUFSIZE because of wraparound at 64K + * on 16 bit machines and because stored blocks are restricted to + * 64K-1 bytes. + */ + } + + /* ========================================================================== + * Send the block data compressed using the given Huffman trees + */ + function zip_compress_block( + ltree, // literal tree + dtree) { // distance tree + var dist; // distance of matched string + var lc; // match length or unmatched char (if dist == 0) + var lx = 0; // running index in l_buf + var dx = 0; // running index in d_buf + var fx = 0; // running index in flag_buf + var flag = 0; // current flags + var code; // the code to send + var extra; // number of extra bits to send + + if (zip_last_lit != 0) do { + if ((lx & 7) == 0) + flag = zip_flag_buf[fx++]; + lc = zip_l_buf[lx++] & 0xff; + if ((flag & 1) == 0) { + zip_SEND_CODE(lc, ltree); /* send a literal byte */ + // Tracecv(isgraph(lc), (stderr," '%c' ", lc)); + } else { + // Here, lc is the match length - MIN_MATCH + code = zip_length_code[lc]; + zip_SEND_CODE(code + zip_LITERALS + 1, ltree); // send the length code + extra = zip_extra_lbits[code]; + if (extra != 0) { + lc -= zip_base_length[code]; + zip_send_bits(lc, extra); // send the extra length bits + } + dist = zip_d_buf[dx++]; + // Here, dist is the match distance - 1 + code = zip_D_CODE(dist); + // Assert (code < D_CODES, "bad d_code"); + + zip_SEND_CODE(code, dtree); // send the distance code + extra = zip_extra_dbits[code]; + if (extra != 0) { + dist -= zip_base_dist[code]; + zip_send_bits(dist, extra); // send the extra distance bits + } + } // literal or match pair ? + flag >>= 1; + } while (lx < zip_last_lit); + + zip_SEND_CODE(zip_END_BLOCK, ltree); + } + + /* ========================================================================== + * Send a value on a given number of bits. + * IN assertion: length <= 16 and value fits in length bits. + */ + var zip_Buf_size = 16; // bit size of bi_buf + function zip_send_bits( + value, // value to send + length) { // number of bits + /* If not enough room in bi_buf, use (valid) bits from bi_buf and + * (16 - bi_valid) bits from value, leaving (width - (16-bi_valid)) + * unused bits in value. + */ + if (zip_bi_valid > zip_Buf_size - length) { + zip_bi_buf |= (value << zip_bi_valid); + zip_put_short(zip_bi_buf); + zip_bi_buf = (value >> (zip_Buf_size - zip_bi_valid)); + zip_bi_valid += length - zip_Buf_size; + } else { + zip_bi_buf |= value << zip_bi_valid; + zip_bi_valid += length; + } + } + + /* ========================================================================== + * Reverse the first len bits of a code, using straightforward code (a faster + * method would use a table) + * IN assertion: 1 <= len <= 15 + */ + function zip_bi_reverse( + code, // the value to invert + len) { // its bit length + var res = 0; + do { + res |= code & 1; + code >>= 1; + res <<= 1; + } while (--len > 0); + return res >> 1; + } + + /* ========================================================================== + * Write out any remaining bits in an incomplete byte. + */ + function zip_bi_windup() { + if (zip_bi_valid > 8) { + zip_put_short(zip_bi_buf); + } else if (zip_bi_valid > 0) { + zip_put_byte(zip_bi_buf); + } + zip_bi_buf = 0; + zip_bi_valid = 0; + } + + function zip_qoutbuf() { + if (zip_outcnt != 0) { + var q, i; + q = zip_new_queue(); + if (zip_qhead == null) + zip_qhead = zip_qtail = q; + else + zip_qtail = zip_qtail.next = q; + q.len = zip_outcnt - zip_outoff; + // System.arraycopy(zip_outbuf, zip_outoff, q.ptr, 0, q.len); + for (i = 0; i < q.len; i++) + q.ptr[i] = zip_outbuf[zip_outoff + i]; + zip_outcnt = zip_outoff = 0; + } + } + + return function deflate(str, level) { + var i, j; + + zip_deflate_data = str; + zip_deflate_pos = 0; + if (typeof level == "undefined") + level = zip_DEFAULT_LEVEL; + zip_deflate_start(level); + + var buff = new Array(1024); + var aout = []; + while ((i = zip_deflate_internal(buff, 0, buff.length)) > 0) { + var cbuf = new Array(i); + for (j = 0; j < i; j++) { + cbuf[j] = String.fromCharCode(buff[j]); + } + aout[aout.length] = cbuf.join(""); + } + zip_deflate_data = null; // G.C. + return aout.join(""); + }; +})(); \ No newline at end of file diff --git a/docs/typescript/js/main.min.2de2acd6b6a32e0298a1ba98d7cf12967985e4b4512bb5e7d65bf74da0009dd4.js b/docs/typescript/js/main.min.2de2acd6b6a32e0298a1ba98d7cf12967985e4b4512bb5e7d65bf74da0009dd4.js new file mode 100644 index 0000000..5e4dba8 --- /dev/null +++ b/docs/typescript/js/main.min.2de2acd6b6a32e0298a1ba98d7cf12967985e4b4512bb5e7d65bf74da0009dd4.js @@ -0,0 +1 @@ +(function(a){'use strict';a(function(){a('[data-toggle="tooltip"]').tooltip(),a('[data-toggle="popover"]').popover(),a('.popover-dismiss').popover({trigger:'focus'})});function b(a){return a.offset().top+a.outerHeight()}a(function(){var c=a(".js-td-cover"),e,f,d;if(!c.length)return;e=b(c),f=a('.js-navbar-scroll').offset().top,d=Math.ceil(a('.js-navbar-scroll').outerHeight()),e-f',a.href='#'+b.id,b.insertAdjacentElement('beforeend',a),b.addEventListener('mouseenter',function(){a.style.visibility='initial'}),b.addEventListener('mouseleave',function(){a.style.visibility='hidden'})}})})}(jQuery),function(a){'use strict';var b={init:function(){a(document).ready(function(){a(document).on('keypress','.td-search-input',function(d){var b,c;if(d.keyCode!==13)return;return b=a(this).val(),c="https://yahoo.github.io/bgdocs/docs/typescript/search/?q="+b,document.location=c,!1})})}};b.init()}(jQuery),function(a){var b=!1,e,c,d;if(a('.language-mermaid').parent().replaceWith(function(){return b=!0,a('
').text(a(this).text())}),!b){mermaid.initialize({startOnLoad:!1});return}e={enable:!0},c=function(a,b){var d={};for(const e in a){const f=e.toLowerCase();a.hasOwnProperty(e)&&b.hasOwnProperty(f)&&(typeof a[e]=="object"?d[e]=c(a[e],b[f]):d[e]=b[f])}return d},d=c(mermaid.mermaidAPI.defaultConfig,e),d.startOnLoad=!0,mermaid.initialize(d)}(jQuery),function(){var c=function(){a=document.createElement('div'),a.classList.add('drawioframe'),b=document.createElement('iframe'),a.appendChild(b),document.body.appendChild(a)},d=function(){a&&(document.body.removeChild(a),a=void 0,b=void 0)},e=function(a,g){var h="https://embed.diagrams.net/",e,f;h+='?embed=1&ui=atlas&spin=1&modified=unsavedChanges&proto=json&saveAndEdit=1&noSaveBtn=1',e=document.createElement('div'),e.classList.add('drawio'),a.parentNode.insertBefore(e,a),e.appendChild(a),f=document.createElement('button'),f.classList.add('drawiobtn'),f.insertAdjacentHTML('beforeend',''),e.appendChild(f),f.addEventListener('click',function(f){if(b)return;c();var e=function(f){var h=b.contentWindow,c,i;if(f.data.length>0&&f.source==h){if(c=JSON.parse(f.data),c.event=='init')h.postMessage(JSON.stringify({action:'load',xml:g}),'*');else if(c.event=='save')i=g.indexOf('data:image/png')==0?'xmlpng':'xmlsvg',h.postMessage(JSON.stringify({action:'export',format:i}),'*');else if(c.event=='export'){const d=a.src.replace(/^.*?([^/]+)$/,'$1'),b=document.createElement('a');b.setAttribute('href',c.data),b.setAttribute('download',d),document.body.appendChild(b),b.click(),b.parentNode.removeChild(b)}(c.event=='exit'||c.event=='export')&&(window.removeEventListener('message',e),d())}};window.addEventListener('message',e),b.setAttribute('src',h)})},b,a;document.addEventListener('DOMContentLoaded',function(){for(const d of document.getElementsByTagName('img')){const c=d,b=c.getAttribute('src');if(!b.endsWith('.svg')&&!b.endsWith('.png'))continue;const a=new XMLHttpRequest;a.responseType='blob',a.open("GET",b),a.addEventListener("load",function(){const b=new FileReader;b.addEventListener('load',function(){if(b.result.indexOf('mxfile')!=-1){const b=new FileReader;b.addEventListener('load',function(){const a=b.result;e(c,a)}),b.readAsDataURL(a.response)}}),b.readAsBinaryString(a.response)}),a.send()}})}()
\ No newline at end of file
diff --git a/docs/typescript/js/prism.js b/docs/typescript/js/prism.js
new file mode 100644
index 0000000..ae881ac
--- /dev/null
+++ b/docs/typescript/js/prism.js
@@ -0,0 +1,21 @@
+/* PrismJS 1.21.0
+https://prismjs.com/download.html#themes=prism&languages=markup+css+clike+javascript+bash+c+csharp+cpp+go+java+markdown+python+scss+sql+toml+yaml&plugins=toolbar+copy-to-clipboard */
+var _self="undefined"!=typeof window?window:"undefined"!=typeof WorkerGlobalScope&&self instanceof WorkerGlobalScope?self:{},Prism=function(u){var c=/\blang(?:uage)?-([\w-]+)\b/i,n=0,M={manual:u.Prism&&u.Prism.manual,disableWorkerMessageHandler:u.Prism&&u.Prism.disableWorkerMessageHandler,util:{encode:function e(n){return n instanceof W?new W(n.type,e(n.content),n.alias):Array.isArray(n)?n.map(e):n.replace(/&/g,"&").replace(/=l.reach);k+=y.value.length,y=y.next){var b=y.value;if(t.length>n.length)return;if(!(b instanceof W)){var x=1;if(h&&y!=t.tail.prev){m.lastIndex=k;var w=m.exec(n);if(!w)break;var A=w.index+(f&&w[1]?w[1].length:0),P=w.index+w[0].length,S=k;for(S+=y.value.length;S<=A;)y=y.next,S+=y.value.length;if(S-=y.value.length,k=S,y.value instanceof W)continue;for(var E=y;E!==t.tail&&(Sl.reach&&(l.reach=j);var C=y.prev;L&&(C=I(t,C,L),k+=L.length),z(t,C,x);var _=new W(o,g?M.tokenize(O,g):O,v,O);y=I(t,C,_),N&&I(t,y,N),1"+a.content+""},!u.document)return u.addEventListener&&(M.disableWorkerMessageHandler||u.addEventListener("message",function(e){var n=JSON.parse(e.data),t=n.language,r=n.code,a=n.immediateClose;u.postMessage(M.highlight(r,M.languages[t],t)),a&&u.close()},!1)),M;var e=M.util.currentScript();function t(){M.manual||M.highlightAll()}if(e&&(M.filename=e.src,e.hasAttribute("data-manual")&&(M.manual=!0)),!M.manual){var r=document.readyState;"loading"===r||"interactive"===r&&e&&e.defer?document.addEventListener("DOMContentLoaded",t):window.requestAnimationFrame?window.requestAnimationFrame(t):window.setTimeout(t,16)}return M}(_self);"undefined"!=typeof module&&module.exports&&(module.exports=Prism),"undefined"!=typeof global&&(global.Prism=Prism);
+Prism.languages.markup={comment://,prolog:/<\?[\s\S]+?\?>/,doctype:{pattern:/"'[\]]|"[^"]*"|'[^']*')+(?:\[(?:[^<"'\]]|"[^"]*"|'[^']*'|<(?!!--)|)*\]\s*)?>/i,greedy:!0,inside:{"internal-subset":{pattern:/(\[)[\s\S]+(?=\]>$)/,lookbehind:!0,greedy:!0,inside:null},string:{pattern:/"[^"]*"|'[^']*'/,greedy:!0},punctuation:/^$|[[\]]/,"doctype-tag":/^DOCTYPE/,name:/[^\s<>'"]+/}},cdata://i,tag:{pattern:/<\/?(?!\d)[^\s>\/=$<%]+(?:\s(?:\s*[^\s>\/=]+(?:\s*=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+(?=[\s>]))|(?=[\s/>])))+)?\s*\/?>/,greedy:!0,inside:{tag:{pattern:/^<\/?[^\s>\/]+/,inside:{punctuation:/^<\/?/,namespace:/^[^\s>\/:]+:/}},"attr-value":{pattern:/=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+)/,inside:{punctuation:[{pattern:/^=/,alias:"attr-equals"},/"|'/]}},punctuation:/\/?>/,"attr-name":{pattern:/[^\s>\/]+/,inside:{namespace:/^[^\s>\/:]+:/}}}},entity:[{pattern:/&[\da-z]{1,8};/i,alias:"named-entity"},/&#x?[\da-f]{1,8};/i]},Prism.languages.markup.tag.inside["attr-value"].inside.entity=Prism.languages.markup.entity,Prism.languages.markup.doctype.inside["internal-subset"].inside=Prism.languages.markup,Prism.hooks.add("wrap",function(a){"entity"===a.type&&(a.attributes.title=a.content.replace(/&/,"&"))}),Object.defineProperty(Prism.languages.markup.tag,"addInlined",{value:function(a,e){var s={};s["language-"+e]={pattern:/(^$)/i,lookbehind:!0,inside:Prism.languages[e]},s.cdata=/^$/i;var n={"included-cdata":{pattern://i,inside:s}};n["language-"+e]={pattern:/[\s\S]+/,inside:Prism.languages[e]};var t={};t[a]={pattern:RegExp("(<__[^]*?>)(?:))*\\]\\]>|(?!)".replace(/__/g,function(){return a}),"i"),lookbehind:!0,greedy:!0,inside:n},Prism.languages.insertBefore("markup","cdata",t)}}),Prism.languages.html=Prism.languages.markup,Prism.languages.mathml=Prism.languages.markup,Prism.languages.svg=Prism.languages.markup,Prism.languages.xml=Prism.languages.extend("markup",{}),Prism.languages.ssml=Prism.languages.xml,Prism.languages.atom=Prism.languages.xml,Prism.languages.rss=Prism.languages.xml;
+!function(e){var s=/("|')(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/;e.languages.css={comment:/\/\*[\s\S]*?\*\//,atrule:{pattern:/@[\w-]+[\s\S]*?(?:;|(?=\s*\{))/,inside:{rule:/^@[\w-]+/,"selector-function-argument":{pattern:/(\bselector\s*\((?!\s*\))\s*)(?:[^()]|\((?:[^()]|\([^()]*\))*\))+?(?=\s*\))/,lookbehind:!0,alias:"selector"},keyword:{pattern:/(^|[^\w-])(?:and|not|only|or)(?![\w-])/,lookbehind:!0}}},url:{pattern:RegExp("\\burl\\((?:"+s.source+"|(?:[^\\\\\r\n()\"']|\\\\[^])*)\\)","i"),greedy:!0,inside:{function:/^url/i,punctuation:/^\(|\)$/,string:{pattern:RegExp("^"+s.source+"$"),alias:"url"}}},selector:RegExp("[^{}\\s](?:[^{};\"']|"+s.source+")*?(?=\\s*\\{)"),string:{pattern:s,greedy:!0},property:/[-_a-z\xA0-\uFFFF][-\w\xA0-\uFFFF]*(?=\s*:)/i,important:/!important\b/i,function:/[-a-z0-9]+(?=\()/i,punctuation:/[(){};:,]/},e.languages.css.atrule.inside.rest=e.languages.css;var t=e.languages.markup;t&&(t.tag.addInlined("style","css"),e.languages.insertBefore("inside","attr-value",{"style-attr":{pattern:/\s*style=("|')(?:\\[\s\S]|(?!\1)[^\\])*\1/i,inside:{"attr-name":{pattern:/^\s*style/i,inside:t.tag.inside},punctuation:/^\s*=\s*['"]|['"]\s*$/,"attr-value":{pattern:/.+/i,inside:e.languages.css}},alias:"language-css"}},t.tag))}(Prism);
+Prism.languages.clike={comment:[{pattern:/(^|[^\\])\/\*[\s\S]*?(?:\*\/|$)/,lookbehind:!0},{pattern:/(^|[^\\:])\/\/.*/,lookbehind:!0,greedy:!0}],string:{pattern:/(["'])(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,greedy:!0},"class-name":{pattern:/(\b(?:class|interface|extends|implements|trait|instanceof|new)\s+|\bcatch\s+\()[\w.\\]+/i,lookbehind:!0,inside:{punctuation:/[.\\]/}},keyword:/\b(?:if|else|while|do|for|return|in|instanceof|function|new|try|throw|catch|finally|null|break|continue)\b/,boolean:/\b(?:true|false)\b/,function:/\w+(?=\()/,number:/\b0x[\da-f]+\b|(?:\b\d+\.?\d*|\B\.\d+)(?:e[+-]?\d+)?/i,operator:/[<>]=?|[!=]=?=?|--?|\+\+?|&&?|\|\|?|[?*/~^%]/,punctuation:/[{}[\];(),.:]/};
+Prism.languages.javascript=Prism.languages.extend("clike",{"class-name":[Prism.languages.clike["class-name"],{pattern:/(^|[^$\w\xA0-\uFFFF])[_$A-Z\xA0-\uFFFF][$\w\xA0-\uFFFF]*(?=\.(?:prototype|constructor))/,lookbehind:!0}],keyword:[{pattern:/((?:^|})\s*)(?:catch|finally)\b/,lookbehind:!0},{pattern:/(^|[^.]|\.\.\.\s*)\b(?:as|async(?=\s*(?:function\b|\(|[$\w\xA0-\uFFFF]|$))|await|break|case|class|const|continue|debugger|default|delete|do|else|enum|export|extends|for|from|function|(?:get|set)(?=\s*[\[$\w\xA0-\uFFFF])|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|static|super|switch|this|throw|try|typeof|undefined|var|void|while|with|yield)\b/,lookbehind:!0}],number:/\b(?:(?:0[xX](?:[\dA-Fa-f](?:_[\dA-Fa-f])?)+|0[bB](?:[01](?:_[01])?)+|0[oO](?:[0-7](?:_[0-7])?)+)n?|(?:\d(?:_\d)?)+n|NaN|Infinity)\b|(?:\b(?:\d(?:_\d)?)+\.?(?:\d(?:_\d)?)*|\B\.(?:\d(?:_\d)?)+)(?:[Ee][+-]?(?:\d(?:_\d)?)+)?/,function:/#?[_$a-zA-Z\xA0-\uFFFF][$\w\xA0-\uFFFF]*(?=\s*(?:\.\s*(?:apply|bind|call)\s*)?\()/,operator:/--|\+\+|\*\*=?|=>|&&=?|\|\|=?|[!=]==|<<=?|>>>?=?|[-+*/%&|^!=<>]=?|\.{3}|\?\?=?|\?\.?|[~:]/}),Prism.languages.javascript["class-name"][0].pattern=/(\b(?:class|interface|extends|implements|instanceof|new)\s+)[\w.\\]+/,Prism.languages.insertBefore("javascript","keyword",{regex:{pattern:/((?:^|[^$\w\xA0-\uFFFF."'\])\s]|\b(?:return|yield))\s*)\/(?:\[(?:[^\]\\\r\n]|\\.)*]|\\.|[^/\\\[\r\n])+\/[gimyus]{0,6}(?=(?:\s|\/\*(?:[^*]|\*(?!\/))*\*\/)*(?:$|[\r\n,.;:})\]]|\/\/))/,lookbehind:!0,greedy:!0},"function-variable":{pattern:/#?[_$a-zA-Z\xA0-\uFFFF][$\w\xA0-\uFFFF]*(?=\s*[=:]\s*(?:async\s*)?(?:\bfunction\b|(?:\((?:[^()]|\([^()]*\))*\)|[_$a-zA-Z\xA0-\uFFFF][$\w\xA0-\uFFFF]*)\s*=>))/,alias:"function"},parameter:[{pattern:/(function(?:\s+[_$A-Za-z\xA0-\uFFFF][$\w\xA0-\uFFFF]*)?\s*\(\s*)(?!\s)(?:[^()]|\([^()]*\))+?(?=\s*\))/,lookbehind:!0,inside:Prism.languages.javascript},{pattern:/[_$a-z\xA0-\uFFFF][$\w\xA0-\uFFFF]*(?=\s*=>)/i,inside:Prism.languages.javascript},{pattern:/(\(\s*)(?!\s)(?:[^()]|\([^()]*\))+?(?=\s*\)\s*=>)/,lookbehind:!0,inside:Prism.languages.javascript},{pattern:/((?:\b|\s|^)(?!(?:as|async|await|break|case|catch|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally|for|from|function|get|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|set|static|super|switch|this|throw|try|typeof|undefined|var|void|while|with|yield)(?![$\w\xA0-\uFFFF]))(?:[_$A-Za-z\xA0-\uFFFF][$\w\xA0-\uFFFF]*\s*)\(\s*|\]\s*\(\s*)(?!\s)(?:[^()]|\([^()]*\))+?(?=\s*\)\s*\{)/,lookbehind:!0,inside:Prism.languages.javascript}],constant:/\b[A-Z](?:[A-Z_]|\dx?)*\b/}),Prism.languages.insertBefore("javascript","string",{"template-string":{pattern:/`(?:\\[\s\S]|\${(?:[^{}]|{(?:[^{}]|{[^}]*})*})+}|(?!\${)[^\\`])*`/,greedy:!0,inside:{"template-punctuation":{pattern:/^`|`$/,alias:"string"},interpolation:{pattern:/((?:^|[^\\])(?:\\{2})*)\${(?:[^{}]|{(?:[^{}]|{[^}]*})*})+}/,lookbehind:!0,inside:{"interpolation-punctuation":{pattern:/^\${|}$/,alias:"punctuation"},rest:Prism.languages.javascript}},string:/[\s\S]+/}}}),Prism.languages.markup&&Prism.languages.markup.tag.addInlined("script","javascript"),Prism.languages.js=Prism.languages.javascript;
+!function(e){var t="\\b(?:BASH|BASHOPTS|BASH_ALIASES|BASH_ARGC|BASH_ARGV|BASH_CMDS|BASH_COMPLETION_COMPAT_DIR|BASH_LINENO|BASH_REMATCH|BASH_SOURCE|BASH_VERSINFO|BASH_VERSION|COLORTERM|COLUMNS|COMP_WORDBREAKS|DBUS_SESSION_BUS_ADDRESS|DEFAULTS_PATH|DESKTOP_SESSION|DIRSTACK|DISPLAY|EUID|GDMSESSION|GDM_LANG|GNOME_KEYRING_CONTROL|GNOME_KEYRING_PID|GPG_AGENT_INFO|GROUPS|HISTCONTROL|HISTFILE|HISTFILESIZE|HISTSIZE|HOME|HOSTNAME|HOSTTYPE|IFS|INSTANCE|JOB|LANG|LANGUAGE|LC_ADDRESS|LC_ALL|LC_IDENTIFICATION|LC_MEASUREMENT|LC_MONETARY|LC_NAME|LC_NUMERIC|LC_PAPER|LC_TELEPHONE|LC_TIME|LESSCLOSE|LESSOPEN|LINES|LOGNAME|LS_COLORS|MACHTYPE|MAILCHECK|MANDATORY_PATH|NO_AT_BRIDGE|OLDPWD|OPTERR|OPTIND|ORBIT_SOCKETDIR|OSTYPE|PAPERSIZE|PATH|PIPESTATUS|PPID|PS1|PS2|PS3|PS4|PWD|RANDOM|REPLY|SECONDS|SELINUX_INIT|SESSION|SESSIONTYPE|SESSION_MANAGER|SHELL|SHELLOPTS|SHLVL|SSH_AUTH_SOCK|TERM|UID|UPSTART_EVENTS|UPSTART_INSTANCE|UPSTART_JOB|UPSTART_SESSION|USER|WINDOWID|XAUTHORITY|XDG_CONFIG_DIRS|XDG_CURRENT_DESKTOP|XDG_DATA_DIRS|XDG_GREETER_DATA_DIR|XDG_MENU_PREFIX|XDG_RUNTIME_DIR|XDG_SEAT|XDG_SEAT_PATH|XDG_SESSION_DESKTOP|XDG_SESSION_ID|XDG_SESSION_PATH|XDG_SESSION_TYPE|XDG_VTNR|XMODIFIERS)\\b",n={environment:{pattern:RegExp("\\$"+t),alias:"constant"},variable:[{pattern:/\$?\(\([\s\S]+?\)\)/,greedy:!0,inside:{variable:[{pattern:/(^\$\(\([\s\S]+)\)\)/,lookbehind:!0},/^\$\(\(/],number:/\b0x[\dA-Fa-f]+\b|(?:\b\d+\.?\d*|\B\.\d+)(?:[Ee]-?\d+)?/,operator:/--?|-=|\+\+?|\+=|!=?|~|\*\*?|\*=|\/=?|%=?|<<=?|>>=?|<=?|>=?|==?|&&?|&=|\^=?|\|\|?|\|=|\?|:/,punctuation:/\(\(?|\)\)?|,|;/}},{pattern:/\$\((?:\([^)]+\)|[^()])+\)|`[^`]+`/,greedy:!0,inside:{variable:/^\$\(|^`|\)$|`$/}},{pattern:/\$\{[^}]+\}/,greedy:!0,inside:{operator:/:[-=?+]?|[!\/]|##?|%%?|\^\^?|,,?/,punctuation:/[\[\]]/,environment:{pattern:RegExp("(\\{)"+t),lookbehind:!0,alias:"constant"}}},/\$(?:\w+|[#?*!@$])/],entity:/\\(?:[abceEfnrtv\\"]|O?[0-7]{1,3}|x[0-9a-fA-F]{1,2}|u[0-9a-fA-F]{4}|U[0-9a-fA-F]{8})/};e.languages.bash={shebang:{pattern:/^#!\s*\/.*/,alias:"important"},comment:{pattern:/(^|[^"{\\$])#.*/,lookbehind:!0},"function-name":[{pattern:/(\bfunction\s+)\w+(?=(?:\s*\(?:\s*\))?\s*\{)/,lookbehind:!0,alias:"function"},{pattern:/\b\w+(?=\s*\(\s*\)\s*\{)/,alias:"function"}],"for-or-select":{pattern:/(\b(?:for|select)\s+)\w+(?=\s+in\s)/,alias:"variable",lookbehind:!0},"assign-left":{pattern:/(^|[\s;|&]|[<>]\()\w+(?=\+?=)/,inside:{environment:{pattern:RegExp("(^|[\\s;|&]|[<>]\\()"+t),lookbehind:!0,alias:"constant"}},alias:"variable",lookbehind:!0},string:[{pattern:/((?:^|[^<])<<-?\s*)(\w+?)\s*(?:\r?\n|\r)[\s\S]*?(?:\r?\n|\r)\2/,lookbehind:!0,greedy:!0,inside:n},{pattern:/((?:^|[^<])<<-?\s*)(["'])(\w+)\2\s*(?:\r?\n|\r)[\s\S]*?(?:\r?\n|\r)\3/,lookbehind:!0,greedy:!0},{pattern:/(^|[^\\](?:\\\\)*)(["'])(?:\\[\s\S]|\$\([^)]+\)|`[^`]+`|(?!\2)[^\\])*\2/,lookbehind:!0,greedy:!0,inside:n}],environment:{pattern:RegExp("\\$?"+t),alias:"constant"},variable:n.variable,function:{pattern:/(^|[\s;|&]|[<>]\()(?:add|apropos|apt|aptitude|apt-cache|apt-get|aspell|automysqlbackup|awk|basename|bash|bc|bconsole|bg|bzip2|cal|cat|cfdisk|chgrp|chkconfig|chmod|chown|chroot|cksum|clear|cmp|column|comm|composer|cp|cron|crontab|csplit|curl|cut|date|dc|dd|ddrescue|debootstrap|df|diff|diff3|dig|dir|dircolors|dirname|dirs|dmesg|du|egrep|eject|env|ethtool|expand|expect|expr|fdformat|fdisk|fg|fgrep|file|find|fmt|fold|format|free|fsck|ftp|fuser|gawk|git|gparted|grep|groupadd|groupdel|groupmod|groups|grub-mkconfig|gzip|halt|head|hg|history|host|hostname|htop|iconv|id|ifconfig|ifdown|ifup|import|install|ip|jobs|join|kill|killall|less|link|ln|locate|logname|logrotate|look|lpc|lpr|lprint|lprintd|lprintq|lprm|ls|lsof|lynx|make|man|mc|mdadm|mkconfig|mkdir|mke2fs|mkfifo|mkfs|mkisofs|mknod|mkswap|mmv|more|most|mount|mtools|mtr|mutt|mv|nano|nc|netstat|nice|nl|nohup|notify-send|npm|nslookup|op|open|parted|passwd|paste|pathchk|ping|pkill|pnpm|popd|pr|printcap|printenv|ps|pushd|pv|quota|quotacheck|quotactl|ram|rar|rcp|reboot|remsync|rename|renice|rev|rm|rmdir|rpm|rsync|scp|screen|sdiff|sed|sendmail|seq|service|sftp|sh|shellcheck|shuf|shutdown|sleep|slocate|sort|split|ssh|stat|strace|su|sudo|sum|suspend|swapon|sync|tac|tail|tar|tee|time|timeout|top|touch|tr|traceroute|tsort|tty|umount|uname|unexpand|uniq|units|unrar|unshar|unzip|update-grub|uptime|useradd|userdel|usermod|users|uudecode|uuencode|v|vdir|vi|vim|virsh|vmstat|wait|watch|wc|wget|whereis|which|who|whoami|write|xargs|xdg-open|yarn|yes|zenity|zip|zsh|zypper)(?=$|[)\s;|&])/,lookbehind:!0},keyword:{pattern:/(^|[\s;|&]|[<>]\()(?:if|then|else|elif|fi|for|while|in|case|esac|function|select|do|done|until)(?=$|[)\s;|&])/,lookbehind:!0},builtin:{pattern:/(^|[\s;|&]|[<>]\()(?:\.|:|break|cd|continue|eval|exec|exit|export|getopts|hash|pwd|readonly|return|shift|test|times|trap|umask|unset|alias|bind|builtin|caller|command|declare|echo|enable|help|let|local|logout|mapfile|printf|read|readarray|source|type|typeset|ulimit|unalias|set|shopt)(?=$|[)\s;|&])/,lookbehind:!0,alias:"class-name"},boolean:{pattern:/(^|[\s;|&]|[<>]\()(?:true|false)(?=$|[)\s;|&])/,lookbehind:!0},"file-descriptor":{pattern:/\B&\d\b/,alias:"important"},operator:{pattern:/\d?<>|>\||\+=|==?|!=?|=~|<<[<-]?|[&\d]?>>|\d?[<>]&?|&[>&]?|\|[&|]?|<=?|>=?/,inside:{"file-descriptor":{pattern:/^\d/,alias:"important"}}},punctuation:/\$?\(\(?|\)\)?|\.\.|[{}[\];\\]/,number:{pattern:/(^|\s)(?:[1-9]\d*|0)(?:[.,]\d+)?\b/,lookbehind:!0}};for(var a=["comment","function-name","for-or-select","assign-left","string","environment","function","keyword","builtin","boolean","file-descriptor","operator","punctuation","number"],r=n.variable[1].inside,s=0;s>=?|<<=?|->|([-+&|:])\1|[?:~]|[-+*/%&|^!=<>]=?/,number:/(?:\b0x(?:[\da-f]+\.?[\da-f]*|\.[\da-f]+)(?:p[+-]?\d+)?|(?:\b\d+\.?\d*|\B\.\d+)(?:e[+-]?\d+)?)[ful]*/i}),Prism.languages.insertBefore("c","string",{macro:{pattern:/(^\s*)#\s*[a-z]+(?:[^\r\n\\/]|\/(?!\*)|\/\*(?:[^*]|\*(?!\/))*\*\/|\\(?:\r\n|[\s\S]))*/im,lookbehind:!0,greedy:!0,alias:"property",inside:{string:[{pattern:/^(#\s*include\s*)<[^>]+>/,lookbehind:!0},Prism.languages.c.string],comment:Prism.languages.c.comment,directive:{pattern:/^(#\s*)[a-z]+/,lookbehind:!0,alias:"keyword"},"directive-hash":/^#/,punctuation:/##|\\(?=[\r\n])/,expression:{pattern:/\S[\s\S]*/,inside:Prism.languages.c}}},constant:/\b(?:__FILE__|__LINE__|__DATE__|__TIME__|__TIMESTAMP__|__func__|EOF|NULL|SEEK_CUR|SEEK_END|SEEK_SET|stdin|stdout|stderr)\b/}),delete Prism.languages.c.boolean;
+!function(s){function a(e,s){return e.replace(/<<(\d+)>>/g,function(e,n){return"(?:"+s[+n]+")"})}function t(e,n,s){return RegExp(a(e,n),s||"")}function e(e,n){for(var s=0;s>/g,function(){return"(?:"+e+")"});return e.replace(/<>/g,"[^\\s\\S]")}var n="bool byte char decimal double dynamic float int long object sbyte short string uint ulong ushort var void",r="class enum interface struct",i="add alias and ascending async await by descending from get global group into join let nameof not notnull on or orderby partial remove select set unmanaged value when where where",o="abstract as base break case catch checked const continue default delegate do else event explicit extern finally fixed for foreach goto if implicit in internal is lock namespace new null operator out override params private protected public readonly ref return sealed sizeof stackalloc static switch this throw try typeof unchecked unsafe using virtual volatile while yield";function l(e){return"\\b(?:"+e.trim().replace(/ /g,"|")+")\\b"}var d=l(r),p=RegExp(l(n+" "+r+" "+i+" "+o)),c=l(r+" "+i+" "+o),u=l(n+" "+r+" "+o),g=e("<(?:[^<>;=+\\-*/%&|^]|<>)*>",2),b=e("\\((?:[^()]|<>)*\\)",2),h="@?\\b[A-Za-z_]\\w*\\b",f=a("<<0>>(?:\\s*<<1>>)?",[h,g]),m=a("(?!<<0>>)<<1>>(?:\\s*\\.\\s*<<1>>)*",[c,f]),k="\\[\\s*(?:,\\s*)*\\]",y=a("<<0>>(?:\\s*(?:\\?\\s*)?<<1>>)*(?:\\s*\\?)?",[m,k]),w=a("(?:<<0>>|<<1>>)(?:\\s*(?:\\?\\s*)?<<2>>)*(?:\\s*\\?)?",[a("\\(<<0>>+(?:,<<0>>+)+\\)",[a("[^,()<>[\\];=+\\-*/%&|^]|<<0>>|<<1>>|<<2>>",[g,b,k])]),m,k]),v={keyword:p,punctuation:/[<>()?,.:[\]]/},x="'(?:[^\r\n'\\\\]|\\\\.|\\\\[Uux][\\da-fA-F]{1,8})'",$='"(?:\\\\.|[^\\\\"\r\n])*"';s.languages.csharp=s.languages.extend("clike",{string:[{pattern:t("(^|[^$\\\\])<<0>>",['@"(?:""|\\\\[^]|[^\\\\"])*"(?!")']),lookbehind:!0,greedy:!0},{pattern:t("(^|[^@$\\\\])<<0>>",[$]),lookbehind:!0,greedy:!0},{pattern:RegExp(x),greedy:!0,alias:"character"}],"class-name":[{pattern:t("(\\busing\\s+static\\s+)<<0>>(?=\\s*;)",[m]),lookbehind:!0,inside:v},{pattern:t("(\\busing\\s+<<0>>\\s*=\\s*)<<1>>(?=\\s*;)",[h,w]),lookbehind:!0,inside:v},{pattern:t("(\\busing\\s+)<<0>>(?=\\s*=)",[h]),lookbehind:!0},{pattern:t("(\\b<<0>>\\s+)<<1>>",[d,f]),lookbehind:!0,inside:v},{pattern:t("(\\bcatch\\s*\\(\\s*)<<0>>",[m]),lookbehind:!0,inside:v},{pattern:t("(\\bwhere\\s+)<<0>>",[h]),lookbehind:!0},{pattern:t("(\\b(?:is(?:\\s+not)?|as)\\s+)<<0>>",[y]),lookbehind:!0,inside:v},{pattern:t("\\b<<0>>(?=\\s+(?!<<1>>)<<2>>(?:\\s*[=,;:{)\\]]|\\s+(?:in|when)\\b))",[w,u,h]),inside:v}],keyword:p,number:/(?:\b0(?:x[\da-f_]*[\da-f]|b[01_]*[01])|(?:\B\.\d+(?:_+\d+)*|\b\d+(?:_+\d+)*(?:\.\d+(?:_+\d+)*)?)(?:e[-+]?\d+(?:_+\d+)*)?)(?:ul|lu|[dflmu])?\b/i,operator:/>>=?|<<=?|[-=]>|([-+&|])\1|~|\?\?=?|[-+*/%&|^!=<>]=?/,punctuation:/\?\.?|::|[{}[\];(),.:]/}),s.languages.insertBefore("csharp","number",{range:{pattern:/\.\./,alias:"operator"}}),s.languages.insertBefore("csharp","punctuation",{"named-parameter":{pattern:t("([(,]\\s*)<<0>>(?=\\s*:)",[h]),lookbehind:!0,alias:"punctuation"}}),s.languages.insertBefore("csharp","class-name",{namespace:{pattern:t("(\\b(?:namespace|using)\\s+)<<0>>(?:\\s*\\.\\s*<<0>>)*(?=\\s*[;{])",[h]),lookbehind:!0,inside:{punctuation:/\./}},"type-expression":{pattern:t("(\\b(?:default|typeof|sizeof)\\s*\\(\\s*)(?:[^()\\s]|\\s(?!\\s*\\))|<<0>>)*(?=\\s*\\))",[b]),lookbehind:!0,alias:"class-name",inside:v},"return-type":{pattern:t("<<0>>(?=\\s+(?:<<1>>\\s*(?:=>|[({]|\\.\\s*this\\s*\\[)|this\\s*\\[))",[w,m]),inside:v,alias:"class-name"},"constructor-invocation":{pattern:t("(\\bnew\\s+)<<0>>(?=\\s*[[({])",[w]),lookbehind:!0,inside:v,alias:"class-name"},"generic-method":{pattern:t("<<0>>\\s*<<1>>(?=\\s*\\()",[h,g]),inside:{function:t("^<<0>>",[h]),generic:{pattern:RegExp(g),alias:"class-name",inside:v}}},"type-list":{pattern:t("\\b((?:<<0>>\\s+<<1>>|where\\s+<<2>>)\\s*:\\s*)(?:<<3>>|<<4>>)(?:\\s*,\\s*(?:<<3>>|<<4>>))*(?=\\s*(?:where|[{;]|=>|$))",[d,f,h,w,p.source]),lookbehind:!0,inside:{keyword:p,"class-name":{pattern:RegExp(w),greedy:!0,inside:v},punctuation:/,/}},preprocessor:{pattern:/(^\s*)#.*/m,lookbehind:!0,alias:"property",inside:{directive:{pattern:/(\s*#)\b(?:define|elif|else|endif|endregion|error|if|line|pragma|region|undef|warning)\b/,lookbehind:!0,alias:"keyword"}}}});var _=$+"|"+x,B=a("/(?![*/])|//[^\r\n]*[\r\n]|/\\*(?:[^*]|\\*(?!/))*\\*/|<<0>>",[_]),E=e(a("[^\"'/()]|<<0>>|\\(<>*\\)",[B]),2),R="\\b(?:assembly|event|field|method|module|param|property|return|type)\\b",P=a("<<0>>(?:\\s*\\(<<1>>*\\))?",[m,E]);s.languages.insertBefore("csharp","class-name",{attribute:{pattern:t("((?:^|[^\\s\\w>)?])\\s*\\[\\s*)(?:<<0>>\\s*:\\s*)?<<1>>(?:\\s*,\\s*<<1>>)*(?=\\s*\\])",[R,P]),lookbehind:!0,greedy:!0,inside:{target:{pattern:t("^<<0>>(?=\\s*:)",[R]),alias:"keyword"},"attribute-arguments":{pattern:t("\\(<<0>>*\\)",[E]),inside:s.languages.csharp},"class-name":{pattern:RegExp(m),inside:{punctuation:/\./}},punctuation:/[:,]/}}});var z=":[^}\r\n]+",S=e(a("[^\"'/()]|<<0>>|\\(<>*\\)",[B]),2),j=a("\\{(?!\\{)(?:(?![}:])<<0>>)*<<1>>?\\}",[S,z]),A=e(a("[^\"'/()]|/(?!\\*)|/\\*(?:[^*]|\\*(?!/))*\\*/|<<0>>|\\(<>*\\)",[_]),2),F=a("\\{(?!\\{)(?:(?![}:])<<0>>)*<<1>>?\\}",[A,z]);function U(e,n){return{interpolation:{pattern:t("((?:^|[^{])(?:\\{\\{)*)<<0>>",[e]),lookbehind:!0,inside:{"format-string":{pattern:t("(^\\{(?:(?![}:])<<0>>)*)<<1>>(?=\\}$)",[n,z]),lookbehind:!0,inside:{punctuation:/^:/}},punctuation:/^\{|\}$/,expression:{pattern:/[\s\S]+/,alias:"language-csharp",inside:s.languages.csharp}}},string:/[\s\S]+/}}s.languages.insertBefore("csharp","string",{"interpolation-string":[{pattern:t('(^|[^\\\\])(?:\\$@|@\\$)"(?:""|\\\\[^]|\\{\\{|<<0>>|[^\\\\{"])*"',[j]),lookbehind:!0,greedy:!0,inside:U(j,S)},{pattern:t('(^|[^@\\\\])\\$"(?:\\\\.|\\{\\{|<<0>>|[^\\\\"{])*"',[F]),lookbehind:!0,greedy:!0,inside:U(F,A)}]})}(Prism),Prism.languages.dotnet=Prism.languages.cs=Prism.languages.csharp;
+!function(e){var t=/\b(?:alignas|alignof|asm|auto|bool|break|case|catch|char|char8_t|char16_t|char32_t|class|compl|concept|const|consteval|constexpr|constinit|const_cast|continue|co_await|co_return|co_yield|decltype|default|delete|do|double|dynamic_cast|else|enum|explicit|export|extern|float|for|friend|goto|if|inline|int|int8_t|int16_t|int32_t|int64_t|uint8_t|uint16_t|uint32_t|uint64_t|long|mutable|namespace|new|noexcept|nullptr|operator|private|protected|public|register|reinterpret_cast|requires|return|short|signed|sizeof|static|static_assert|static_cast|struct|switch|template|this|thread_local|throw|try|typedef|typeid|typename|union|unsigned|using|virtual|void|volatile|wchar_t|while)\b/;e.languages.cpp=e.languages.extend("c",{"class-name":[{pattern:RegExp("(\\b(?:class|concept|enum|struct|typename)\\s+)(?!)\\w+".replace(//g,function(){return t.source})),lookbehind:!0},/\b[A-Z]\w*(?=\s*::\s*\w+\s*\()/,/\b[A-Z_]\w*(?=\s*::\s*~\w+\s*\()/i,/\w+(?=\s*<(?:[^<>]|<(?:[^<>]|<[^<>]*>)*>)*>\s*::\s*\w+\s*\()/],keyword:t,number:{pattern:/(?:\b0b[01']+|\b0x(?:[\da-f']+\.?[\da-f']*|\.[\da-f']+)(?:p[+-]?[\d']+)?|(?:\b[\d']+\.?[\d']*|\B\.[\d']+)(?:e[+-]?[\d']+)?)[ful]*/i,greedy:!0},operator:/>>=?|<<=?|->|([-+&|:])\1|[?:~]|<=>|[-+*/%&|^!=<>]=?|\b(?:and|and_eq|bitand|bitor|not|not_eq|or|or_eq|xor|xor_eq)\b/,boolean:/\b(?:true|false)\b/}),e.languages.insertBefore("cpp","string",{"raw-string":{pattern:/R"([^()\\ ]{0,16})\([\s\S]*?\)\1"/,alias:"string",greedy:!0}}),e.languages.insertBefore("cpp","class-name",{"base-clause":{pattern:/(\b(?:class|struct)\s+\w+\s*:\s*)(?:[^;{}"'])+?(?=\s*[;{])/,lookbehind:!0,greedy:!0,inside:e.languages.extend("cpp",{})}}),e.languages.insertBefore("inside","operator",{"class-name":/\b[a-z_]\w*\b(?!\s*::)/i},e.languages.cpp["base-clause"])}(Prism);
+Prism.languages.go=Prism.languages.extend("clike",{keyword:/\b(?:break|case|chan|const|continue|default|defer|else|fallthrough|for|func|go(?:to)?|if|import|interface|map|package|range|return|select|struct|switch|type|var)\b/,builtin:/\b(?:bool|byte|complex(?:64|128)|error|float(?:32|64)|rune|string|u?int(?:8|16|32|64)?|uintptr|append|cap|close|complex|copy|delete|imag|len|make|new|panic|print(?:ln)?|real|recover)\b/,boolean:/\b(?:_|iota|nil|true|false)\b/,operator:/[*\/%^!=]=?|\+[=+]?|-[=-]?|\|[=|]?|&(?:=|&|\^=?)?|>(?:>=?|=)?|<(?:<=?|=|-)?|:=|\.\.\./,number:/(?:\b0x[a-f\d]+|(?:\b\d+\.?\d*|\B\.\d+)(?:e[-+]?\d+)?)i?/i,string:{pattern:/(["'`])(?:\\[\s\S]|(?!\1)[^\\])*\1/,greedy:!0}}),delete Prism.languages.go["class-name"];
+!function(e){var t=/\b(?:abstract|assert|boolean|break|byte|case|catch|char|class|const|continue|default|do|double|else|enum|exports|extends|final|finally|float|for|goto|if|implements|import|instanceof|int|interface|long|module|native|new|null|open|opens|package|private|protected|provides|public|record|requires|return|short|static|strictfp|super|switch|synchronized|this|throw|throws|to|transient|transitive|try|uses|var|void|volatile|while|with|yield)\b/,a=/\b[A-Z](?:\w*[a-z]\w*)?\b/;e.languages.java=e.languages.extend("clike",{"class-name":[a,/\b[A-Z]\w*(?=\s+\w+\s*[;,=())])/],keyword:t,function:[e.languages.clike.function,{pattern:/(\:\:)[a-z_]\w*/,lookbehind:!0}],number:/\b0b[01][01_]*L?\b|\b0x[\da-f_]*\.?[\da-f_p+-]+\b|(?:\b\d[\d_]*\.?[\d_]*|\B\.\d[\d_]*)(?:e[+-]?\d[\d_]*)?[dfl]?/i,operator:{pattern:/(^|[^.])(?:<<=?|>>>?=?|->|--|\+\+|&&|\|\||::|[?:~]|[-+*/%&|^!=<>]=?)/m,lookbehind:!0}}),e.languages.insertBefore("java","string",{"triple-quoted-string":{pattern:/"""[ \t]*[\r\n](?:(?:"|"")?(?:\\.|[^"\\]))*"""/,greedy:!0,alias:"string"}}),e.languages.insertBefore("java","class-name",{annotation:{alias:"punctuation",pattern:/(^|[^.])@\w+/,lookbehind:!0},namespace:{pattern:RegExp("(\\b(?:exports|import(?:\\s+static)?|module|open|opens|package|provides|requires|to|transitive|uses|with)\\s+)(?!)[a-z]\\w*(?:\\.[a-z]\\w*)*\\.?".replace(//g,function(){return t.source})),lookbehind:!0,inside:{punctuation:/\./}},generics:{pattern:/<(?:[\w\s,.&?]|<(?:[\w\s,.&?]|<(?:[\w\s,.&?]|<[\w\s,.&?]*>)*>)*>)*>/,inside:{"class-name":a,keyword:t,punctuation:/[<>(),.:]/,operator:/[?&|]/}}})}(Prism);
+!function(d){function n(n){return n=n.replace(//g,function(){return"(?:\\\\.|[^\\\\\n\r]|(?:\n|\r\n?)(?!\n|\r\n?))"}),RegExp("((?:^|[^\\\\])(?:\\\\{2})*)(?:"+n+")")}var e="(?:\\\\.|``(?:[^`\r\n]|`(?!`))+``|`[^`\r\n]+`|[^\\\\|\r\n`])+",t="\\|?__(?:\\|__)+\\|?(?:(?:\n|\r\n?)|$)".replace(/__/g,function(){return e}),a="\\|?[ \t]*:?-{3,}:?[ \t]*(?:\\|[ \t]*:?-{3,}:?[ \t]*)+\\|?(?:\n|\r\n?)";d.languages.markdown=d.languages.extend("markup",{}),d.languages.insertBefore("markdown","prolog",{blockquote:{pattern:/^>(?:[\t ]*>)*/m,alias:"punctuation"},table:{pattern:RegExp("^"+t+a+"(?:"+t+")*","m"),inside:{"table-data-rows":{pattern:RegExp("^("+t+a+")(?:"+t+")*$"),lookbehind:!0,inside:{"table-data":{pattern:RegExp(e),inside:d.languages.markdown},punctuation:/\|/}},"table-line":{pattern:RegExp("^("+t+")"+a+"$"),lookbehind:!0,inside:{punctuation:/\||:?-{3,}:?/}},"table-header-row":{pattern:RegExp("^"+t+"$"),inside:{"table-header":{pattern:RegExp(e),alias:"important",inside:d.languages.markdown},punctuation:/\|/}}}},code:[{pattern:/((?:^|\n)[ \t]*\n|(?:^|\r\n?)[ \t]*\r\n?)(?: {4}|\t).+(?:(?:\n|\r\n?)(?: {4}|\t).+)*/,lookbehind:!0,alias:"keyword"},{pattern:/``.+?``|`[^`\r\n]+`/,alias:"keyword"},{pattern:/^```[\s\S]*?^```$/m,greedy:!0,inside:{"code-block":{pattern:/^(```.*(?:\n|\r\n?))[\s\S]+?(?=(?:\n|\r\n?)^```$)/m,lookbehind:!0},"code-language":{pattern:/^(```).+/,lookbehind:!0},punctuation:/```/}}],title:[{pattern:/\S.*(?:\n|\r\n?)(?:==+|--+)(?=[ \t]*$)/m,alias:"important",inside:{punctuation:/==+$|--+$/}},{pattern:/(^\s*)#+.+/m,lookbehind:!0,alias:"important",inside:{punctuation:/^#+|#+$/}}],hr:{pattern:/(^\s*)([*-])(?:[\t ]*\2){2,}(?=\s*$)/m,lookbehind:!0,alias:"punctuation"},list:{pattern:/(^\s*)(?:[*+-]|\d+\.)(?=[\t ].)/m,lookbehind:!0,alias:"punctuation"},"url-reference":{pattern:/!?\[[^\]]+\]:[\t ]+(?:\S+|<(?:\\.|[^>\\])+>)(?:[\t ]+(?:"(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'|\((?:\\.|[^)\\])*\)))?/,inside:{variable:{pattern:/^(!?\[)[^\]]+/,lookbehind:!0},string:/(?:"(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'|\((?:\\.|[^)\\])*\))$/,punctuation:/^[\[\]!:]|[<>]/},alias:"url"},bold:{pattern:n("\\b__(?:(?!_)|_(?:(?!_))+_)+__\\b|\\*\\*(?:(?!\\*)|\\*(?:(?!\\*))+\\*)+\\*\\*"),lookbehind:!0,greedy:!0,inside:{content:{pattern:/(^..)[\s\S]+(?=..$)/,lookbehind:!0,inside:{}},punctuation:/\*\*|__/}},italic:{pattern:n("\\b_(?:(?!_)|__(?:(?!_))+__)+_\\b|\\*(?:(?!\\*)|\\*\\*(?:(?!\\*))+\\*\\*)+\\*"),lookbehind:!0,greedy:!0,inside:{content:{pattern:/(^.)[\s\S]+(?=.$)/,lookbehind:!0,inside:{}},punctuation:/[*_]/}},strike:{pattern:n("(~~?)(?:(?!~))+?\\2"),lookbehind:!0,greedy:!0,inside:{content:{pattern:/(^~~?)[\s\S]+(?=\1$)/,lookbehind:!0,inside:{}},punctuation:/~~?/}},url:{pattern:n('!?\\[(?:(?!\\]))+\\](?:\\([^\\s)]+(?:[\t ]+"(?:\\\\.|[^"\\\\])*")?\\)| ?\\[(?:(?!\\]))+\\])'),lookbehind:!0,greedy:!0,inside:{variable:{pattern:/(\[)[^\]]+(?=\]$)/,lookbehind:!0},content:{pattern:/(^!?\[)[^\]]+(?=\])/,lookbehind:!0,inside:{}},string:{pattern:/"(?:\\.|[^"\\])*"(?=\)$)/}}}}),["url","bold","italic","strike"].forEach(function(e){["url","bold","italic","strike"].forEach(function(n){e!==n&&(d.languages.markdown[e].inside.content.inside[n]=d.languages.markdown[n])})}),d.hooks.add("after-tokenize",function(n){"markdown"!==n.language&&"md"!==n.language||!function n(e){if(e&&"string"!=typeof e)for(var t=0,a=e.length;t]?|>[=>]?|[&|^~]/,punctuation:/[{}[\];(),.:]/},Prism.languages.python["string-interpolation"].inside.interpolation.inside.rest=Prism.languages.python,Prism.languages.py=Prism.languages.python;
+Prism.languages.scss=Prism.languages.extend("css",{comment:{pattern:/(^|[^\\])(?:\/\*[\s\S]*?\*\/|\/\/.*)/,lookbehind:!0},atrule:{pattern:/@[\w-]+(?:\([^()]+\)|[^(])*?(?=\s+[{;])/,inside:{rule:/@[\w-]+/}},url:/(?:[-a-z]+-)?url(?=\()/i,selector:{pattern:/(?=\S)[^@;{}()]?(?:[^@;{}()]|#\{\$[-\w]+\})+(?=\s*\{(?:\}|\s|[^}]+[:{][^}]+))/m,inside:{parent:{pattern:/&/,alias:"important"},placeholder:/%[-\w]+/,variable:/\$[-\w]+|#\{\$[-\w]+\}/}},property:{pattern:/(?:[\w-]|\$[-\w]+|#\{\$[-\w]+\})+(?=\s*:)/,inside:{variable:/\$[-\w]+|#\{\$[-\w]+\}/}}}),Prism.languages.insertBefore("scss","atrule",{keyword:[/@(?:if|else(?: if)?|for|each|while|import|extend|debug|warn|mixin|include|function|return|content)/i,{pattern:/( +)(?:from|through)(?= )/,lookbehind:!0}]}),Prism.languages.insertBefore("scss","important",{variable:/\$[-\w]+|#\{\$[-\w]+\}/}),Prism.languages.insertBefore("scss","function",{placeholder:{pattern:/%[-\w]+/,alias:"selector"},statement:{pattern:/\B!(?:default|optional)\b/i,alias:"keyword"},boolean:/\b(?:true|false)\b/,null:{pattern:/\bnull\b/,alias:"keyword"},operator:{pattern:/(\s)(?:[-+*\/%]|[=!]=|<=?|>=?|and|or|not)(?=\s)/,lookbehind:!0}}),Prism.languages.scss.atrule.inside.rest=Prism.languages.scss;
+Prism.languages.sql={comment:{pattern:/(^|[^\\])(?:\/\*[\s\S]*?\*\/|(?:--|\/\/|#).*)/,lookbehind:!0},variable:[{pattern:/@(["'`])(?:\\[\s\S]|(?!\1)[^\\])+\1/,greedy:!0},/@[\w.$]+/],string:{pattern:/(^|[^@\\])("|')(?:\\[\s\S]|(?!\2)[^\\]|\2\2)*\2/,greedy:!0,lookbehind:!0},function:/\b(?:AVG|COUNT|FIRST|FORMAT|LAST|LCASE|LEN|MAX|MID|MIN|MOD|NOW|ROUND|SUM|UCASE)(?=\s*\()/i,keyword:/\b(?:ACTION|ADD|AFTER|ALGORITHM|ALL|ALTER|ANALYZE|ANY|APPLY|AS|ASC|AUTHORIZATION|AUTO_INCREMENT|BACKUP|BDB|BEGIN|BERKELEYDB|BIGINT|BINARY|BIT|BLOB|BOOL|BOOLEAN|BREAK|BROWSE|BTREE|BULK|BY|CALL|CASCADED?|CASE|CHAIN|CHAR(?:ACTER|SET)?|CHECK(?:POINT)?|CLOSE|CLUSTERED|COALESCE|COLLATE|COLUMNS?|COMMENT|COMMIT(?:TED)?|COMPUTE|CONNECT|CONSISTENT|CONSTRAINT|CONTAINS(?:TABLE)?|CONTINUE|CONVERT|CREATE|CROSS|CURRENT(?:_DATE|_TIME|_TIMESTAMP|_USER)?|CURSOR|CYCLE|DATA(?:BASES?)?|DATE(?:TIME)?|DAY|DBCC|DEALLOCATE|DEC|DECIMAL|DECLARE|DEFAULT|DEFINER|DELAYED|DELETE|DELIMITERS?|DENY|DESC|DESCRIBE|DETERMINISTIC|DISABLE|DISCARD|DISK|DISTINCT|DISTINCTROW|DISTRIBUTED|DO|DOUBLE|DROP|DUMMY|DUMP(?:FILE)?|DUPLICATE|ELSE(?:IF)?|ENABLE|ENCLOSED|END|ENGINE|ENUM|ERRLVL|ERRORS|ESCAPED?|EXCEPT|EXEC(?:UTE)?|EXISTS|EXIT|EXPLAIN|EXTENDED|FETCH|FIELDS|FILE|FILLFACTOR|FIRST|FIXED|FLOAT|FOLLOWING|FOR(?: EACH ROW)?|FORCE|FOREIGN|FREETEXT(?:TABLE)?|FROM|FULL|FUNCTION|GEOMETRY(?:COLLECTION)?|GLOBAL|GOTO|GRANT|GROUP|HANDLER|HASH|HAVING|HOLDLOCK|HOUR|IDENTITY(?:_INSERT|COL)?|IF|IGNORE|IMPORT|INDEX|INFILE|INNER|INNODB|INOUT|INSERT|INT|INTEGER|INTERSECT|INTERVAL|INTO|INVOKER|ISOLATION|ITERATE|JOIN|KEYS?|KILL|LANGUAGE|LAST|LEAVE|LEFT|LEVEL|LIMIT|LINENO|LINES|LINESTRING|LOAD|LOCAL|LOCK|LONG(?:BLOB|TEXT)|LOOP|MATCH(?:ED)?|MEDIUM(?:BLOB|INT|TEXT)|MERGE|MIDDLEINT|MINUTE|MODE|MODIFIES|MODIFY|MONTH|MULTI(?:LINESTRING|POINT|POLYGON)|NATIONAL|NATURAL|NCHAR|NEXT|NO|NONCLUSTERED|NULLIF|NUMERIC|OFF?|OFFSETS?|ON|OPEN(?:DATASOURCE|QUERY|ROWSET)?|OPTIMIZE|OPTION(?:ALLY)?|ORDER|OUT(?:ER|FILE)?|OVER|PARTIAL|PARTITION|PERCENT|PIVOT|PLAN|POINT|POLYGON|PRECEDING|PRECISION|PREPARE|PREV|PRIMARY|PRINT|PRIVILEGES|PROC(?:EDURE)?|PUBLIC|PURGE|QUICK|RAISERROR|READS?|REAL|RECONFIGURE|REFERENCES|RELEASE|RENAME|REPEAT(?:ABLE)?|REPLACE|REPLICATION|REQUIRE|RESIGNAL|RESTORE|RESTRICT|RETURN(?:S|ING)?|REVOKE|RIGHT|ROLLBACK|ROUTINE|ROW(?:COUNT|GUIDCOL|S)?|RTREE|RULE|SAVE(?:POINT)?|SCHEMA|SECOND|SELECT|SERIAL(?:IZABLE)?|SESSION(?:_USER)?|SET(?:USER)?|SHARE|SHOW|SHUTDOWN|SIMPLE|SMALLINT|SNAPSHOT|SOME|SONAME|SQL|START(?:ING)?|STATISTICS|STATUS|STRIPED|SYSTEM_USER|TABLES?|TABLESPACE|TEMP(?:ORARY|TABLE)?|TERMINATED|TEXT(?:SIZE)?|THEN|TIME(?:STAMP)?|TINY(?:BLOB|INT|TEXT)|TOP?|TRAN(?:SACTIONS?)?|TRIGGER|TRUNCATE|TSEQUAL|TYPES?|UNBOUNDED|UNCOMMITTED|UNDEFINED|UNION|UNIQUE|UNLOCK|UNPIVOT|UNSIGNED|UPDATE(?:TEXT)?|USAGE|USE|USER|USING|VALUES?|VAR(?:BINARY|CHAR|CHARACTER|YING)|VIEW|WAITFOR|WARNINGS|WHEN|WHERE|WHILE|WITH(?: ROLLUP|IN)?|WORK|WRITE(?:TEXT)?|YEAR)\b/i,boolean:/\b(?:TRUE|FALSE|NULL)\b/i,number:/\b0x[\da-f]+\b|\b\d+\.?\d*|\B\.\d+\b/i,operator:/[-+*\/=%^~]|&&?|\|\|?|!=?|<(?:=>?|<|>)?|>[>=]?|\b(?:AND|BETWEEN|IN|LIKE|NOT|OR|IS|DIV|REGEXP|RLIKE|SOUNDS LIKE|XOR)\b/i,punctuation:/[;[\]()`,.]/};
+!function(e){function n(e){return e.replace(/__/g,function(){return"(?:[\\w-]+|'[^'\n\r]*'|\"(?:\\\\.|[^\\\\\"\r\n])*\")"})}e.languages.toml={comment:{pattern:/#.*/,greedy:!0},table:{pattern:RegExp(n("(^\\s*\\[\\s*(?:\\[\\s*)?)__(?:\\s*\\.\\s*__)*(?=\\s*\\])"),"m"),lookbehind:!0,greedy:!0,alias:"class-name"},key:{pattern:RegExp(n("(^\\s*|[{,]\\s*)__(?:\\s*\\.\\s*__)*(?=\\s*=)"),"m"),lookbehind:!0,greedy:!0,alias:"property"},string:{pattern:/"""(?:\\[\s\S]|[^\\])*?"""|'''[\s\S]*?'''|'[^'\n\r]*'|"(?:\\.|[^\\"\r\n])*"/,greedy:!0},date:[{pattern:/\b\d{4}-\d{2}-\d{2}(?:[T\s]\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z|[+-]\d{2}:\d{2})?)?\b/i,alias:"number"},{pattern:/\b\d{2}:\d{2}:\d{2}(?:\.\d+)?\b/,alias:"number"}],number:/(?:\b0(?:x[\da-zA-Z]+(?:_[\da-zA-Z]+)*|o[0-7]+(?:_[0-7]+)*|b[10]+(?:_[10]+)*))\b|[-+]?\b\d+(?:_\d+)*(?:\.\d+(?:_\d+)*)?(?:[eE][+-]?\d+(?:_\d+)*)?\b|[-+]?\b(?:inf|nan)\b/,boolean:/\b(?:true|false)\b/,punctuation:/[.,=[\]{}]/}}(Prism);
+!function(n){var t=/[*&][^\s[\]{},]+/,e=/!(?:<[\w\-%#;/?:@&=+$,.!~*'()[\]]+>|(?:[a-zA-Z\d-]*!)?[\w\-%#;/?:@&=+$.~*'()]+)?/,r="(?:"+e.source+"(?:[ \t]+"+t.source+")?|"+t.source+"(?:[ \t]+"+e.source+")?)";function a(n,t){t=(t||"").replace(/m/g,"")+"m";var e="([:\\-,[{]\\s*(?:\\s<>[ \t]+)?)(?:<>)(?=[ \t]*(?:$|,|]|}|\\s*#))".replace(/<>/g,function(){return r}).replace(/<>/g,function(){return n});return RegExp(e,t)}n.languages.yaml={scalar:{pattern:RegExp("([\\-:]\\s*(?:\\s<>[ \t]+)?[|>])[ \t]*(?:((?:\r?\n|\r)[ \t]+)[^\r\n]+(?:\\2[^\r\n]+)*)".replace(/<>/g,function(){return r})),lookbehind:!0,alias:"string"},comment:/#.*/,key:{pattern:RegExp("((?:^|[:\\-,[{\r\n?])[ \t]*(?:<>[ \t]+)?)[^\r\n{[\\]},#\\s]+?(?=\\s*:\\s)".replace(/<>/g,function(){return r})),lookbehind:!0,alias:"atrule"},directive:{pattern:/(^[ \t]*)%.+/m,lookbehind:!0,alias:"important"},datetime:{pattern:a("\\d{4}-\\d\\d?-\\d\\d?(?:[tT]|[ \t]+)\\d\\d?:\\d{2}:\\d{2}(?:\\.\\d*)?[ \t]*(?:Z|[-+]\\d\\d?(?::\\d{2})?)?|\\d{4}-\\d{2}-\\d{2}|\\d\\d?:\\d{2}(?::\\d{2}(?:\\.\\d*)?)?"),lookbehind:!0,alias:"number"},boolean:{pattern:a("true|false","i"),lookbehind:!0,alias:"important"},null:{pattern:a("null|~","i"),lookbehind:!0,alias:"important"},string:{pattern:a("(\"|')(?:(?!\\2)[^\\\\\r\n]|\\\\.)*\\2"),lookbehind:!0,greedy:!0},number:{pattern:a("[+-]?(?:0x[\\da-f]+|0o[0-7]+|(?:\\d+\\.?\\d*|\\.?\\d+)(?:e[+-]?\\d+)?|\\.inf|\\.nan)","i"),lookbehind:!0},tag:e,important:t,punctuation:/---|[:[\]{}\-,|>?]|\.\.\./},n.languages.yml=n.languages.yaml}(Prism);
+!function(){if("undefined"!=typeof self&&self.Prism&&self.document){var i=[],l={},c=function(){};Prism.plugins.toolbar={};var e=Prism.plugins.toolbar.registerButton=function(e,n){var t;t="function"==typeof n?n:function(e){var t;return"function"==typeof n.onClick?((t=document.createElement("button")).type="button",t.addEventListener("click",function(){n.onClick.call(this,e)})):"string"==typeof n.url?(t=document.createElement("a")).href=n.url:t=document.createElement("span"),n.className&&t.classList.add(n.className),t.textContent=n.text,t},e in l?console.warn('There is a button with the key "'+e+'" registered already.'):i.push(l[e]=t)},t=Prism.plugins.toolbar.hook=function(a){var e=a.element.parentNode;if(e&&/pre/i.test(e.nodeName)&&!e.parentNode.classList.contains("code-toolbar")){var t=document.createElement("div");t.classList.add("code-toolbar"),e.parentNode.insertBefore(t,e),t.appendChild(e);var r=document.createElement("div");r.classList.add("toolbar");var n=i,o=function(e){for(;e;){var t=e.getAttribute("data-toolbar-order");if(null!=t)return(t=t.trim()).length?t.split(/\s*,\s*/g):[];e=e.parentElement}}(a.element);o&&(n=o.map(function(e){return l[e]||c})),n.forEach(function(e){var t=e(a);if(t){var n=document.createElement("div");n.classList.add("toolbar-item"),n.appendChild(t),r.appendChild(n)}}),t.appendChild(r)}};e("label",function(e){var t=e.element.parentNode;if(t&&/pre/i.test(t.nodeName)&&t.hasAttribute("data-label")){var n,a,r=t.getAttribute("data-label");try{a=document.querySelector("template#"+r)}catch(e){}return a?n=a.content:(t.hasAttribute("data-url")?(n=document.createElement("a")).href=t.getAttribute("data-url"):n=document.createElement("span"),n.textContent=r),n}}),Prism.hooks.add("complete",t)}}();
+!function(){if("undefined"!=typeof self&&self.Prism&&self.document)if(Prism.plugins.toolbar){var i=window.ClipboardJS||void 0;i||"function"!=typeof require||(i=require("clipboard"));var c=[];if(!i){var o=document.createElement("script"),t=document.querySelector("head");o.onload=function(){if(i=window.ClipboardJS)for(;c.length;)c.pop()()},o.src="https://cdnjs.cloudflare.com/ajax/libs/clipboard.js/2.0.0/clipboard.min.js",t.appendChild(o)}Prism.plugins.toolbar.registerButton("copy-to-clipboard",function(o){var t=document.createElement("button");t.textContent="Copy";var e=o.element;return i?n():c.push(n),t;function n(){var o=new i(t,{text:function(){return e.textContent}});o.on("success",function(){t.textContent="Copied!",r()}),o.on("error",function(){t.textContent="Press Ctrl+C to copy",r()})}function r(){setTimeout(function(){t.textContent="Copy"},5e3)}})}else console.warn("Copy to Clipboard plugin loaded before Toolbar plugin.")}();
diff --git a/docs/typescript/js/swagger-ui-bundle.js b/docs/typescript/js/swagger-ui-bundle.js
new file mode 100644
index 0000000..c48cc4c
--- /dev/null
+++ b/docs/typescript/js/swagger-ui-bundle.js
@@ -0,0 +1,134 @@
+!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t(function(){try{return require("esprima")}catch(e){}}()):"function"==typeof define&&define.amd?define(["esprima"],t):"object"==typeof exports?exports.SwaggerUIBundle=t(function(){try{return require("esprima")}catch(e){}}()):e.SwaggerUIBundle=t(e.esprima)}(window,function(e){return function(e){var t={};function n(r){if(t[r])return t[r].exports;var o=t[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}return n.m=e,n.c=t,n.d=function(e,t,r){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)n.d(r,o,function(t){return e[t]}.bind(null,o));return r},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="/dist",n(n.s=488)}([function(e,t,n){"use strict";e.exports=n(104)},function(e,t,n){e.exports=function(){"use strict";var e=Array.prototype.slice;function t(e,t){t&&(e.prototype=Object.create(t.prototype)),e.prototype.constructor=e}function n(e){return a(e)?e:J(e)}function r(e){return s(e)?e:K(e)}function o(e){return u(e)?e:Y(e)}function i(e){return a(e)&&!c(e)?e:$(e)}function a(e){return!(!e||!e[p])}function s(e){return!(!e||!e[f])}function u(e){return!(!e||!e[h])}function c(e){return s(e)||u(e)}function l(e){return!(!e||!e[d])}t(r,n),t(o,n),t(i,n),n.isIterable=a,n.isKeyed=s,n.isIndexed=u,n.isAssociative=c,n.isOrdered=l,n.Keyed=r,n.Indexed=o,n.Set=i;var p="@@__IMMUTABLE_ITERABLE__@@",f="@@__IMMUTABLE_KEYED__@@",h="@@__IMMUTABLE_INDEXED__@@",d="@@__IMMUTABLE_ORDERED__@@",m=5,v=1<>>0;if(""+n!==t||4294967295===n)return NaN;t=n}return t<0?C(e)+t:t}function O(){return!0}function A(e,t,n){return(0===e||void 0!==n&&e<=-n)&&(void 0===t||void 0!==n&&t>=n)}function T(e,t){return P(e,t,0)}function j(e,t){return P(e,t,t)}function P(e,t,n){return void 0===e?n:e<0?Math.max(0,t+e):void 0===t?e:Math.min(t,e)}var I=0,M=1,N=2,R="function"==typeof Symbol&&Symbol.iterator,D="@@iterator",L=R||D;function U(e){this.next=e}function q(e,t,n,r){var o=0===e?t:1===e?n:[t,n];return r?r.value=o:r={value:o,done:!1},r}function F(){return{value:void 0,done:!0}}function B(e){return!!H(e)}function z(e){return e&&"function"==typeof e.next}function V(e){var t=H(e);return t&&t.call(e)}function H(e){var t=e&&(R&&e[R]||e[D]);if("function"==typeof t)return t}function W(e){return e&&"number"==typeof e.length}function J(e){return null==e?ie():a(e)?e.toSeq():function(e){var t=ue(e)||"object"==typeof e&&new te(e);if(!t)throw new TypeError("Expected Array or iterable object of values, or keyed object: "+e);return t}(e)}function K(e){return null==e?ie().toKeyedSeq():a(e)?s(e)?e.toSeq():e.fromEntrySeq():ae(e)}function Y(e){return null==e?ie():a(e)?s(e)?e.entrySeq():e.toIndexedSeq():se(e)}function $(e){return(null==e?ie():a(e)?s(e)?e.entrySeq():e:se(e)).toSetSeq()}U.prototype.toString=function(){return"[Iterator]"},U.KEYS=I,U.VALUES=M,U.ENTRIES=N,U.prototype.inspect=U.prototype.toSource=function(){return this.toString()},U.prototype[L]=function(){return this},t(J,n),J.of=function(){return J(arguments)},J.prototype.toSeq=function(){return this},J.prototype.toString=function(){return this.__toString("Seq {","}")},J.prototype.cacheResult=function(){return!this._cache&&this.__iterateUncached&&(this._cache=this.entrySeq().toArray(),this.size=this._cache.length),this},J.prototype.__iterate=function(e,t){return ce(this,e,t,!0)},J.prototype.__iterator=function(e,t){return le(this,e,t,!0)},t(K,J),K.prototype.toKeyedSeq=function(){return this},t(Y,J),Y.of=function(){return Y(arguments)},Y.prototype.toIndexedSeq=function(){return this},Y.prototype.toString=function(){return this.__toString("Seq [","]")},Y.prototype.__iterate=function(e,t){return ce(this,e,t,!1)},Y.prototype.__iterator=function(e,t){return le(this,e,t,!1)},t($,J),$.of=function(){return $(arguments)},$.prototype.toSetSeq=function(){return this},J.isSeq=oe,J.Keyed=K,J.Set=$,J.Indexed=Y;var G,Z,X,Q="@@__IMMUTABLE_SEQ__@@";function ee(e){this._array=e,this.size=e.length}function te(e){var t=Object.keys(e);this._object=e,this._keys=t,this.size=t.length}function ne(e){this._iterable=e,this.size=e.length||e.size}function re(e){this._iterator=e,this._iteratorCache=[]}function oe(e){return!(!e||!e[Q])}function ie(){return G||(G=new ee([]))}function ae(e){var t=Array.isArray(e)?new ee(e).fromEntrySeq():z(e)?new re(e).fromEntrySeq():B(e)?new ne(e).fromEntrySeq():"object"==typeof e?new te(e):void 0;if(!t)throw new TypeError("Expected Array or iterable object of [k, v] entries, or keyed object: "+e);return t}function se(e){var t=ue(e);if(!t)throw new TypeError("Expected Array or iterable object of values: "+e);return t}function ue(e){return W(e)?new ee(e):z(e)?new re(e):B(e)?new ne(e):void 0}function ce(e,t,n,r){var o=e._cache;if(o){for(var i=o.length-1,a=0;a<=i;a++){var s=o[n?i-a:a];if(!1===t(s[1],r?s[0]:a,e))return a+1}return a}return e.__iterateUncached(t,n)}function le(e,t,n,r){var o=e._cache;if(o){var i=o.length-1,a=0;return new U(function(){var e=o[n?i-a:a];return a++>i?{value:void 0,done:!0}:q(t,r?e[0]:a-1,e[1])})}return e.__iteratorUncached(t,n)}function pe(e,t){return t?function e(t,n,r,o){return Array.isArray(n)?t.call(o,r,Y(n).map(function(r,o){return e(t,r,o,n)})):he(n)?t.call(o,r,K(n).map(function(r,o){return e(t,r,o,n)})):n}(t,e,"",{"":e}):fe(e)}function fe(e){return Array.isArray(e)?Y(e).map(fe).toList():he(e)?K(e).map(fe).toMap():e}function he(e){return e&&(e.constructor===Object||void 0===e.constructor)}function de(e,t){if(e===t||e!=e&&t!=t)return!0;if(!e||!t)return!1;if("function"==typeof e.valueOf&&"function"==typeof t.valueOf){if((e=e.valueOf())===(t=t.valueOf())||e!=e&&t!=t)return!0;if(!e||!t)return!1}return!("function"!=typeof e.equals||"function"!=typeof t.equals||!e.equals(t))}function me(e,t){if(e===t)return!0;if(!a(t)||void 0!==e.size&&void 0!==t.size&&e.size!==t.size||void 0!==e.__hash&&void 0!==t.__hash&&e.__hash!==t.__hash||s(e)!==s(t)||u(e)!==u(t)||l(e)!==l(t))return!1;if(0===e.size&&0===t.size)return!0;var n=!c(e);if(l(e)){var r=e.entries();return t.every(function(e,t){var o=r.next().value;return o&&de(o[1],e)&&(n||de(o[0],t))})&&r.next().done}var o=!1;if(void 0===e.size)if(void 0===t.size)"function"==typeof e.cacheResult&&e.cacheResult();else{o=!0;var i=e;e=t,t=i}var p=!0,f=t.__iterate(function(t,r){if(n?!e.has(t):o?!de(t,e.get(r,y)):!de(e.get(r,y),t))return p=!1,!1});return p&&e.size===f}function ve(e,t){if(!(this instanceof ve))return new ve(e,t);if(this._value=e,this.size=void 0===t?1/0:Math.max(0,t),0===this.size){if(Z)return Z;Z=this}}function ge(e,t){if(!e)throw new Error(t)}function ye(e,t,n){if(!(this instanceof ye))return new ye(e,t,n);if(ge(0!==n,"Cannot step a Range by 0"),e=e||0,void 0===t&&(t=1/0),n=void 0===n?1:Math.abs(n),tr?{value:void 0,done:!0}:q(e,o,n[t?r-o++:o++])})},t(te,K),te.prototype.get=function(e,t){return void 0===t||this.has(e)?this._object[e]:t},te.prototype.has=function(e){return this._object.hasOwnProperty(e)},te.prototype.__iterate=function(e,t){for(var n=this._object,r=this._keys,o=r.length-1,i=0;i<=o;i++){var a=r[t?o-i:i];if(!1===e(n[a],a,this))return i+1}return i},te.prototype.__iterator=function(e,t){var n=this._object,r=this._keys,o=r.length-1,i=0;return new U(function(){var a=r[t?o-i:i];return i++>o?{value:void 0,done:!0}:q(e,a,n[a])})},te.prototype[d]=!0,t(ne,Y),ne.prototype.__iterateUncached=function(e,t){if(t)return this.cacheResult().__iterate(e,t);var n=V(this._iterable),r=0;if(z(n))for(var o;!(o=n.next()).done&&!1!==e(o.value,r++,this););return r},ne.prototype.__iteratorUncached=function(e,t){if(t)return this.cacheResult().__iterator(e,t);var n=V(this._iterable);if(!z(n))return new U(F);var r=0;return new U(function(){var t=n.next();return t.done?t:q(e,r++,t.value)})},t(re,Y),re.prototype.__iterateUncached=function(e,t){if(t)return this.cacheResult().__iterate(e,t);for(var n,r=this._iterator,o=this._iteratorCache,i=0;i=r.length){var t=n.next();if(t.done)return t;r[o]=t.value}return q(e,o,r[o++])})},t(ve,Y),ve.prototype.toString=function(){return 0===this.size?"Repeat []":"Repeat [ "+this._value+" "+this.size+" times ]"},ve.prototype.get=function(e,t){return this.has(e)?this._value:t},ve.prototype.includes=function(e){return de(this._value,e)},ve.prototype.slice=function(e,t){var n=this.size;return A(e,t,n)?this:new ve(this._value,j(t,n)-T(e,n))},ve.prototype.reverse=function(){return this},ve.prototype.indexOf=function(e){return de(this._value,e)?0:-1},ve.prototype.lastIndexOf=function(e){return de(this._value,e)?this.size:-1},ve.prototype.__iterate=function(e,t){for(var n=0;n=0&&t=0&&nn?{value:void 0,done:!0}:q(e,i++,a)})},ye.prototype.equals=function(e){return e instanceof ye?this._start===e._start&&this._end===e._end&&this._step===e._step:me(this,e)},t(be,n),t(_e,be),t(we,be),t(xe,be),be.Keyed=_e,be.Indexed=we,be.Set=xe;var Ee="function"==typeof Math.imul&&-2===Math.imul(4294967295,2)?Math.imul:function(e,t){var n=65535&(e|=0),r=65535&(t|=0);return n*r+((e>>>16)*r+n*(t>>>16)<<16>>>0)|0};function Se(e){return e>>>1&1073741824|3221225471&e}function Ce(e){if(!1===e||null==e)return 0;if("function"==typeof e.valueOf&&(!1===(e=e.valueOf())||null==e))return 0;if(!0===e)return 1;var t=typeof e;if("number"===t){if(e!=e||e===1/0)return 0;var n=0|e;for(n!==e&&(n^=4294967295*e);e>4294967295;)n^=e/=4294967295;return Se(n)}if("string"===t)return e.length>Me?function(e){var t=De[e];return void 0===t&&(t=ke(e),Re===Ne&&(Re=0,De={}),Re++,De[e]=t),t}(e):ke(e);if("function"==typeof e.hashCode)return e.hashCode();if("object"===t)return function(e){var t;if(je&&void 0!==(t=Oe.get(e)))return t;if(void 0!==(t=e[Ie]))return t;if(!Te){if(void 0!==(t=e.propertyIsEnumerable&&e.propertyIsEnumerable[Ie]))return t;if(void 0!==(t=function(e){if(e&&e.nodeType>0)switch(e.nodeType){case 1:return e.uniqueID;case 9:return e.documentElement&&e.documentElement.uniqueID}}(e)))return t}if(t=++Pe,1073741824&Pe&&(Pe=0),je)Oe.set(e,t);else{if(void 0!==Ae&&!1===Ae(e))throw new Error("Non-extensible objects are not allowed as keys.");if(Te)Object.defineProperty(e,Ie,{enumerable:!1,configurable:!1,writable:!1,value:t});else if(void 0!==e.propertyIsEnumerable&&e.propertyIsEnumerable===e.constructor.prototype.propertyIsEnumerable)e.propertyIsEnumerable=function(){return this.constructor.prototype.propertyIsEnumerable.apply(this,arguments)},e.propertyIsEnumerable[Ie]=t;else{if(void 0===e.nodeType)throw new Error("Unable to set a non-enumerable property on object.");e[Ie]=t}}return t}(e);if("function"==typeof e.toString)return ke(e.toString());throw new Error("Value type "+t+" cannot be hashed.")}function ke(e){for(var t=0,n=0;n=t.length)throw new Error("Missing value for key: "+t[n]);e.set(t[n],t[n+1])}})},Ue.prototype.toString=function(){return this.__toString("Map {","}")},Ue.prototype.get=function(e,t){return this._root?this._root.get(0,void 0,e,t):t},Ue.prototype.set=function(e,t){return Qe(this,e,t)},Ue.prototype.setIn=function(e,t){return this.updateIn(e,y,function(){return t})},Ue.prototype.remove=function(e){return Qe(this,e,y)},Ue.prototype.deleteIn=function(e){return this.updateIn(e,function(){return y})},Ue.prototype.update=function(e,t,n){return 1===arguments.length?e(this):this.updateIn([e],t,n)},Ue.prototype.updateIn=function(e,t,n){n||(n=t,t=void 0);var r=function e(t,n,r,o){var i=t===y,a=n.next();if(a.done){var s=i?r:t,u=o(s);return u===s?t:u}ge(i||t&&t.set,"invalid keyPath");var c=a.value,l=i?y:t.get(c,y),p=e(l,n,r,o);return p===l?t:p===y?t.remove(c):(i?Xe():t).set(c,p)}(this,rn(e),t,n);return r===y?void 0:r},Ue.prototype.clear=function(){return 0===this.size?this:this.__ownerID?(this.size=0,this._root=null,this.__hash=void 0,this.__altered=!0,this):Xe()},Ue.prototype.merge=function(){return rt(this,void 0,arguments)},Ue.prototype.mergeWith=function(t){var n=e.call(arguments,1);return rt(this,t,n)},Ue.prototype.mergeIn=function(t){var n=e.call(arguments,1);return this.updateIn(t,Xe(),function(e){return"function"==typeof e.merge?e.merge.apply(e,n):n[n.length-1]})},Ue.prototype.mergeDeep=function(){return rt(this,ot,arguments)},Ue.prototype.mergeDeepWith=function(t){var n=e.call(arguments,1);return rt(this,it(t),n)},Ue.prototype.mergeDeepIn=function(t){var n=e.call(arguments,1);return this.updateIn(t,Xe(),function(e){return"function"==typeof e.mergeDeep?e.mergeDeep.apply(e,n):n[n.length-1]})},Ue.prototype.sort=function(e){return Tt(Jt(this,e))},Ue.prototype.sortBy=function(e,t){return Tt(Jt(this,t,e))},Ue.prototype.withMutations=function(e){var t=this.asMutable();return e(t),t.wasAltered()?t.__ensureOwner(this.__ownerID):this},Ue.prototype.asMutable=function(){return this.__ownerID?this:this.__ensureOwner(new E)},Ue.prototype.asImmutable=function(){return this.__ensureOwner()},Ue.prototype.wasAltered=function(){return this.__altered},Ue.prototype.__iterator=function(e,t){return new Ye(this,e,t)},Ue.prototype.__iterate=function(e,t){var n=this,r=0;return this._root&&this._root.iterate(function(t){return r++,e(t[1],t[0],n)},t),r},Ue.prototype.__ensureOwner=function(e){return e===this.__ownerID?this:e?Ze(this.size,this._root,e,this.__hash):(this.__ownerID=e,this.__altered=!1,this)},Ue.isMap=qe;var Fe,Be="@@__IMMUTABLE_MAP__@@",ze=Ue.prototype;function Ve(e,t){this.ownerID=e,this.entries=t}function He(e,t,n){this.ownerID=e,this.bitmap=t,this.nodes=n}function We(e,t,n){this.ownerID=e,this.count=t,this.nodes=n}function Je(e,t,n){this.ownerID=e,this.keyHash=t,this.entries=n}function Ke(e,t,n){this.ownerID=e,this.keyHash=t,this.entry=n}function Ye(e,t,n){this._type=t,this._reverse=n,this._stack=e._root&&Ge(e._root)}function $e(e,t){return q(e,t[0],t[1])}function Ge(e,t){return{node:e,index:0,__prev:t}}function Ze(e,t,n,r){var o=Object.create(ze);return o.size=e,o._root=t,o.__ownerID=n,o.__hash=r,o.__altered=!1,o}function Xe(){return Fe||(Fe=Ze(0))}function Qe(e,t,n){var r,o;if(e._root){var i=w(b),a=w(_);if(r=et(e._root,e.__ownerID,0,void 0,t,n,i,a),!a.value)return e;o=e.size+(i.value?n===y?-1:1:0)}else{if(n===y)return e;o=1,r=new Ve(e.__ownerID,[[t,n]])}return e.__ownerID?(e.size=o,e._root=r,e.__hash=void 0,e.__altered=!0,e):r?Ze(o,r):Xe()}function et(e,t,n,r,o,i,a,s){return e?e.update(t,n,r,o,i,a,s):i===y?e:(x(s),x(a),new Ke(t,r,[o,i]))}function tt(e){return e.constructor===Ke||e.constructor===Je}function nt(e,t,n,r,o){if(e.keyHash===r)return new Je(t,r,[e.entry,o]);var i,a=(0===n?e.keyHash:e.keyHash>>>n)&g,s=(0===n?r:r>>>n)&g;return new He(t,1<>1&1431655765))+(e>>2&858993459))+(e>>4)&252645135,e+=e>>8,127&(e+=e>>16)}function ut(e,t,n,r){var o=r?e:S(e);return o[t]=n,o}ze[Be]=!0,ze.delete=ze.remove,ze.removeIn=ze.deleteIn,Ve.prototype.get=function(e,t,n,r){for(var o=this.entries,i=0,a=o.length;i=ct)return function(e,t,n,r){e||(e=new E);for(var o=new Ke(e,Ce(n),[n,r]),i=0;i>>e)&g),i=this.bitmap;return 0==(i&o)?r:this.nodes[st(i&o-1)].get(e+m,t,n,r)},He.prototype.update=function(e,t,n,r,o,i,a){void 0===n&&(n=Ce(r));var s=(0===t?n:n>>>t)&g,u=1<=lt)return function(e,t,n,r,o){for(var i=0,a=new Array(v),s=0;0!==n;s++,n>>>=1)a[s]=1&n?t[i++]:void 0;return a[r]=o,new We(e,i+1,a)}(e,f,c,s,d);if(l&&!d&&2===f.length&&tt(f[1^p]))return f[1^p];if(l&&d&&1===f.length&&tt(d))return d;var b=e&&e===this.ownerID,_=l?d?c:c^u:c|u,w=l?d?ut(f,p,d,b):function(e,t,n){var r=e.length-1;if(n&&t===r)return e.pop(),e;for(var o=new Array(r),i=0,a=0;a>>e)&g,i=this.nodes[o];return i?i.get(e+m,t,n,r):r},We.prototype.update=function(e,t,n,r,o,i,a){void 0===n&&(n=Ce(r));var s=(0===t?n:n>>>t)&g,u=o===y,c=this.nodes,l=c[s];if(u&&!l)return this;var p=et(l,e,t+m,n,r,o,i,a);if(p===l)return this;var f=this.count;if(l){if(!p&&--f0&&r=0&&e=e.size||t<0)return e.withMutations(function(e){t<0?kt(e,t).set(0,n):kt(e,0,t+1).set(t,n)});t+=e._origin;var r=e._tail,o=e._root,i=w(_);return t>=At(e._capacity)?r=Et(r,e.__ownerID,0,t,n,i):o=Et(o,e.__ownerID,e._level,t,n,i),i.value?e.__ownerID?(e._root=o,e._tail=r,e.__hash=void 0,e.__altered=!0,e):wt(e._origin,e._capacity,e._level,o,r):e}(this,e,t)},ft.prototype.remove=function(e){return this.has(e)?0===e?this.shift():e===this.size-1?this.pop():this.splice(e,1):this},ft.prototype.insert=function(e,t){return this.splice(e,0,t)},ft.prototype.clear=function(){return 0===this.size?this:this.__ownerID?(this.size=this._origin=this._capacity=0,this._level=m,this._root=this._tail=null,this.__hash=void 0,this.__altered=!0,this):xt()},ft.prototype.push=function(){var e=arguments,t=this.size;return this.withMutations(function(n){kt(n,0,t+e.length);for(var r=0;r>>t&g;if(r>=this.array.length)return new vt([],e);var o,i=0===r;if(t>0){var a=this.array[r];if((o=a&&a.removeBefore(e,t-m,n))===a&&i)return this}if(i&&!o)return this;var s=St(this,e);if(!i)for(var u=0;u>>t&g;if(o>=this.array.length)return this;if(t>0){var i=this.array[o];if((r=i&&i.removeAfter(e,t-m,n))===i&&o===this.array.length-1)return this}var a=St(this,e);return a.array.splice(o+1),r&&(a.array[o]=r),a};var gt,yt,bt={};function _t(e,t){var n=e._origin,r=e._capacity,o=At(r),i=e._tail;return a(e._root,e._level,0);function a(e,s,u){return 0===s?function(e,a){var s=a===o?i&&i.array:e&&e.array,u=a>n?0:n-a,c=r-a;return c>v&&(c=v),function(){if(u===c)return bt;var e=t?--c:u++;return s&&s[e]}}(e,u):function(e,o,i){var s,u=e&&e.array,c=i>n?0:n-i>>o,l=1+(r-i>>o);return l>v&&(l=v),function(){for(;;){if(s){var e=s();if(e!==bt)return e;s=null}if(c===l)return bt;var n=t?--l:c++;s=a(u&&u[n],o-m,i+(n<>>n&g,u=e&&s0){var c=e&&e.array[s],l=Et(c,t,n-m,r,o,i);return l===c?e:((a=St(e,t)).array[s]=l,a)}return u&&e.array[s]===o?e:(x(i),a=St(e,t),void 0===o&&s===a.array.length-1?a.array.pop():a.array[s]=o,a)}function St(e,t){return t&&e&&t===e.ownerID?e:new vt(e?e.array.slice():[],t)}function Ct(e,t){if(t>=At(e._capacity))return e._tail;if(t<1<0;)n=n.array[t>>>r&g],r-=m;return n}}function kt(e,t,n){void 0!==t&&(t|=0),void 0!==n&&(n|=0);var r=e.__ownerID||new E,o=e._origin,i=e._capacity,a=o+t,s=void 0===n?i:n<0?i+n:o+n;if(a===o&&s===i)return e;if(a>=s)return e.clear();for(var u=e._level,c=e._root,l=0;a+l<0;)c=new vt(c&&c.array.length?[void 0,c]:[],r),l+=1<<(u+=m);l&&(a+=l,o+=l,s+=l,i+=l);for(var p=At(i),f=At(s);f>=1<p?new vt([],r):h;if(h&&f>p&&am;y-=m){var b=p>>>y&g;v=v.array[b]=St(v.array[b],r)}v.array[p>>>m&g]=h}if(s=f)a-=f,s-=f,u=m,c=null,d=d&&d.removeBefore(r,0,a);else if(a>o||f>>u&g;if(_!==f>>>u&g)break;_&&(l+=(1<o&&(c=c.removeBefore(r,u,a-l)),c&&fi&&(i=c.size),a(u)||(c=c.map(function(e){return pe(e)})),r.push(c)}return i>e.size&&(e=e.setSize(i)),at(e,t,r)}function At(e){return e>>m<=v&&a.size>=2*i.size?(r=(o=a.filter(function(e,t){return void 0!==e&&s!==t})).toKeyedSeq().map(function(e){return e[0]}).flip().toMap(),e.__ownerID&&(r.__ownerID=o.__ownerID=e.__ownerID)):(r=i.remove(t),o=s===a.size-1?a.pop():a.set(s,void 0))}else if(u){if(n===a.get(s)[1])return e;r=i,o=a.set(s,[t,n])}else r=i.set(t,a.size),o=a.set(a.size,[t,n]);return e.__ownerID?(e.size=r.size,e._map=r,e._list=o,e.__hash=void 0,e):Pt(r,o)}function Nt(e,t){this._iter=e,this._useKeys=t,this.size=e.size}function Rt(e){this._iter=e,this.size=e.size}function Dt(e){this._iter=e,this.size=e.size}function Lt(e){this._iter=e,this.size=e.size}function Ut(e){var t=en(e);return t._iter=e,t.size=e.size,t.flip=function(){return e},t.reverse=function(){var t=e.reverse.apply(this);return t.flip=function(){return e.reverse()},t},t.has=function(t){return e.includes(t)},t.includes=function(t){return e.has(t)},t.cacheResult=tn,t.__iterateUncached=function(t,n){var r=this;return e.__iterate(function(e,n){return!1!==t(n,e,r)},n)},t.__iteratorUncached=function(t,n){if(t===N){var r=e.__iterator(t,n);return new U(function(){var e=r.next();if(!e.done){var t=e.value[0];e.value[0]=e.value[1],e.value[1]=t}return e})}return e.__iterator(t===M?I:M,n)},t}function qt(e,t,n){var r=en(e);return r.size=e.size,r.has=function(t){return e.has(t)},r.get=function(r,o){var i=e.get(r,y);return i===y?o:t.call(n,i,r,e)},r.__iterateUncached=function(r,o){var i=this;return e.__iterate(function(e,o,a){return!1!==r(t.call(n,e,o,a),o,i)},o)},r.__iteratorUncached=function(r,o){var i=e.__iterator(N,o);return new U(function(){var o=i.next();if(o.done)return o;var a=o.value,s=a[0];return q(r,s,t.call(n,a[1],s,e),o)})},r}function Ft(e,t){var n=en(e);return n._iter=e,n.size=e.size,n.reverse=function(){return e},e.flip&&(n.flip=function(){var t=Ut(e);return t.reverse=function(){return e.flip()},t}),n.get=function(n,r){return e.get(t?n:-1-n,r)},n.has=function(n){return e.has(t?n:-1-n)},n.includes=function(t){return e.includes(t)},n.cacheResult=tn,n.__iterate=function(t,n){var r=this;return e.__iterate(function(e,n){return t(e,n,r)},!n)},n.__iterator=function(t,n){return e.__iterator(t,!n)},n}function Bt(e,t,n,r){var o=en(e);return r&&(o.has=function(r){var o=e.get(r,y);return o!==y&&!!t.call(n,o,r,e)},o.get=function(r,o){var i=e.get(r,y);return i!==y&&t.call(n,i,r,e)?i:o}),o.__iterateUncached=function(o,i){var a=this,s=0;return e.__iterate(function(e,i,u){if(t.call(n,e,i,u))return s++,o(e,r?i:s-1,a)},i),s},o.__iteratorUncached=function(o,i){var a=e.__iterator(N,i),s=0;return new U(function(){for(;;){var i=a.next();if(i.done)return i;var u=i.value,c=u[0],l=u[1];if(t.call(n,l,c,e))return q(o,r?c:s++,l,i)}})},o}function zt(e,t,n,r){var o=e.size;if(void 0!==t&&(t|=0),void 0!==n&&(n===1/0?n=o:n|=0),A(t,n,o))return e;var i=T(t,o),a=j(n,o);if(i!=i||a!=a)return zt(e.toSeq().cacheResult(),t,n,r);var s,u=a-i;u==u&&(s=u<0?0:u);var c=en(e);return c.size=0===s?s:e.size&&s||void 0,!r&&oe(e)&&s>=0&&(c.get=function(t,n){return(t=k(this,t))>=0&&ts)return{value:void 0,done:!0};var e=o.next();return r||t===M?e:q(t,u-1,t===I?void 0:e.value[1],e)})},c}function Vt(e,t,n,r){var o=en(e);return o.__iterateUncached=function(o,i){var a=this;if(i)return this.cacheResult().__iterate(o,i);var s=!0,u=0;return e.__iterate(function(e,i,c){if(!s||!(s=t.call(n,e,i,c)))return u++,o(e,r?i:u-1,a)}),u},o.__iteratorUncached=function(o,i){var a=this;if(i)return this.cacheResult().__iterator(o,i);var s=e.__iterator(N,i),u=!0,c=0;return new U(function(){var e,i,l;do{if((e=s.next()).done)return r||o===M?e:q(o,c++,o===I?void 0:e.value[1],e);var p=e.value;i=p[0],l=p[1],u&&(u=t.call(n,l,i,a))}while(u);return o===N?e:q(o,i,l,e)})},o}function Ht(e,t){var n=s(e),o=[e].concat(t).map(function(e){return a(e)?n&&(e=r(e)):e=n?ae(e):se(Array.isArray(e)?e:[e]),e}).filter(function(e){return 0!==e.size});if(0===o.length)return e;if(1===o.length){var i=o[0];if(i===e||n&&s(i)||u(e)&&u(i))return i}var c=new ee(o);return n?c=c.toKeyedSeq():u(e)||(c=c.toSetSeq()),(c=c.flatten(!0)).size=o.reduce(function(e,t){if(void 0!==e){var n=t.size;if(void 0!==n)return e+n}},0),c}function Wt(e,t,n){var r=en(e);return r.__iterateUncached=function(r,o){var i=0,s=!1;return function e(u,c){var l=this;u.__iterate(function(o,u){return(!t||c0}function $t(e,t,r){var o=en(e);return o.size=new ee(r).map(function(e){return e.size}).min(),o.__iterate=function(e,t){for(var n,r=this.__iterator(M,t),o=0;!(n=r.next()).done&&!1!==e(n.value,o++,this););return o},o.__iteratorUncached=function(e,o){var i=r.map(function(e){return e=n(e),V(o?e.reverse():e)}),a=0,s=!1;return new U(function(){var n;return s||(n=i.map(function(e){return e.next()}),s=n.some(function(e){return e.done})),s?{value:void 0,done:!0}:q(e,a++,t.apply(null,n.map(function(e){return e.value})))})},o}function Gt(e,t){return oe(e)?t:e.constructor(t)}function Zt(e){if(e!==Object(e))throw new TypeError("Expected [K, V] tuple: "+e)}function Xt(e){return Le(e.size),C(e)}function Qt(e){return s(e)?r:u(e)?o:i}function en(e){return Object.create((s(e)?K:u(e)?Y:$).prototype)}function tn(){return this._iter.cacheResult?(this._iter.cacheResult(),this.size=this._iter.size,this):J.prototype.cacheResult.call(this)}function nn(e,t){return e>t?1:e=0;n--)t={value:arguments[n],next:t};return this.__ownerID?(this.size=e,this._head=t,this.__hash=void 0,this.__altered=!0,this):An(e,t)},En.prototype.pushAll=function(e){if(0===(e=o(e)).size)return this;Le(e.size);var t=this.size,n=this._head;return e.reverse().forEach(function(e){t++,n={value:e,next:n}}),this.__ownerID?(this.size=t,this._head=n,this.__hash=void 0,this.__altered=!0,this):An(t,n)},En.prototype.pop=function(){return this.slice(1)},En.prototype.unshift=function(){return this.push.apply(this,arguments)},En.prototype.unshiftAll=function(e){return this.pushAll(e)},En.prototype.shift=function(){return this.pop.apply(this,arguments)},En.prototype.clear=function(){return 0===this.size?this:this.__ownerID?(this.size=0,this._head=void 0,this.__hash=void 0,this.__altered=!0,this):Tn()},En.prototype.slice=function(e,t){if(A(e,t,this.size))return this;var n=T(e,this.size);if(j(t,this.size)!==this.size)return we.prototype.slice.call(this,e,t);for(var r=this.size-n,o=this._head;n--;)o=o.next;return this.__ownerID?(this.size=r,this._head=o,this.__hash=void 0,this.__altered=!0,this):An(r,o)},En.prototype.__ensureOwner=function(e){return e===this.__ownerID?this:e?An(this.size,this._head,e,this.__hash):(this.__ownerID=e,this.__altered=!1,this)},En.prototype.__iterate=function(e,t){if(t)return this.reverse().__iterate(e);for(var n=0,r=this._head;r&&!1!==e(r.value,n++,this);)r=r.next;return n},En.prototype.__iterator=function(e,t){if(t)return this.reverse().__iterator(e);var n=0,r=this._head;return new U(function(){if(r){var t=r.value;return r=r.next,q(e,n++,t)}return{value:void 0,done:!0}})},En.isStack=Sn;var Cn,kn="@@__IMMUTABLE_STACK__@@",On=En.prototype;function An(e,t,n,r){var o=Object.create(On);return o.size=e,o._head=t,o.__ownerID=n,o.__hash=r,o.__altered=!1,o}function Tn(){return Cn||(Cn=An(0))}function jn(e,t){var n=function(n){e.prototype[n]=t[n]};return Object.keys(t).forEach(n),Object.getOwnPropertySymbols&&Object.getOwnPropertySymbols(t).forEach(n),e}On[kn]=!0,On.withMutations=ze.withMutations,On.asMutable=ze.asMutable,On.asImmutable=ze.asImmutable,On.wasAltered=ze.wasAltered,n.Iterator=U,jn(n,{toArray:function(){Le(this.size);var e=new Array(this.size||0);return this.valueSeq().__iterate(function(t,n){e[n]=t}),e},toIndexedSeq:function(){return new Rt(this)},toJS:function(){return this.toSeq().map(function(e){return e&&"function"==typeof e.toJS?e.toJS():e}).__toJS()},toJSON:function(){return this.toSeq().map(function(e){return e&&"function"==typeof e.toJSON?e.toJSON():e}).__toJS()},toKeyedSeq:function(){return new Nt(this,!0)},toMap:function(){return Ue(this.toKeyedSeq())},toObject:function(){Le(this.size);var e={};return this.__iterate(function(t,n){e[n]=t}),e},toOrderedMap:function(){return Tt(this.toKeyedSeq())},toOrderedSet:function(){return gn(s(this)?this.valueSeq():this)},toSet:function(){return cn(s(this)?this.valueSeq():this)},toSetSeq:function(){return new Dt(this)},toSeq:function(){return u(this)?this.toIndexedSeq():s(this)?this.toKeyedSeq():this.toSetSeq()},toStack:function(){return En(s(this)?this.valueSeq():this)},toList:function(){return ft(s(this)?this.valueSeq():this)},toString:function(){return"[Iterable]"},__toString:function(e,t){return 0===this.size?e+t:e+" "+this.toSeq().map(this.__toStringMapper).join(", ")+" "+t},concat:function(){var t=e.call(arguments,0);return Gt(this,Ht(this,t))},includes:function(e){return this.some(function(t){return de(t,e)})},entries:function(){return this.__iterator(N)},every:function(e,t){Le(this.size);var n=!0;return this.__iterate(function(r,o,i){if(!e.call(t,r,o,i))return n=!1,!1}),n},filter:function(e,t){return Gt(this,Bt(this,e,t,!0))},find:function(e,t,n){var r=this.findEntry(e,t);return r?r[1]:n},forEach:function(e,t){return Le(this.size),this.__iterate(t?e.bind(t):e)},join:function(e){Le(this.size),e=void 0!==e?""+e:",";var t="",n=!0;return this.__iterate(function(r){n?n=!1:t+=e,t+=null!=r?r.toString():""}),t},keys:function(){return this.__iterator(I)},map:function(e,t){return Gt(this,qt(this,e,t))},reduce:function(e,t,n){var r,o;return Le(this.size),arguments.length<2?o=!0:r=t,this.__iterate(function(t,i,a){o?(o=!1,r=t):r=e.call(n,r,t,i,a)}),r},reduceRight:function(e,t,n){var r=this.toKeyedSeq().reverse();return r.reduce.apply(r,arguments)},reverse:function(){return Gt(this,Ft(this,!0))},slice:function(e,t){return Gt(this,zt(this,e,t,!0))},some:function(e,t){return!this.every(Rn(e),t)},sort:function(e){return Gt(this,Jt(this,e))},values:function(){return this.__iterator(M)},butLast:function(){return this.slice(0,-1)},isEmpty:function(){return void 0!==this.size?0===this.size:!this.some(function(){return!0})},count:function(e,t){return C(e?this.toSeq().filter(e,t):this)},countBy:function(e,t){return function(e,t,n){var r=Ue().asMutable();return e.__iterate(function(o,i){r.update(t.call(n,o,i,e),0,function(e){return e+1})}),r.asImmutable()}(this,e,t)},equals:function(e){return me(this,e)},entrySeq:function(){var e=this;if(e._cache)return new ee(e._cache);var t=e.toSeq().map(Nn).toIndexedSeq();return t.fromEntrySeq=function(){return e.toSeq()},t},filterNot:function(e,t){return this.filter(Rn(e),t)},findEntry:function(e,t,n){var r=n;return this.__iterate(function(n,o,i){if(e.call(t,n,o,i))return r=[o,n],!1}),r},findKey:function(e,t){var n=this.findEntry(e,t);return n&&n[0]},findLast:function(e,t,n){return this.toKeyedSeq().reverse().find(e,t,n)},findLastEntry:function(e,t,n){return this.toKeyedSeq().reverse().findEntry(e,t,n)},findLastKey:function(e,t){return this.toKeyedSeq().reverse().findKey(e,t)},first:function(){return this.find(O)},flatMap:function(e,t){return Gt(this,function(e,t,n){var r=Qt(e);return e.toSeq().map(function(o,i){return r(t.call(n,o,i,e))}).flatten(!0)}(this,e,t))},flatten:function(e){return Gt(this,Wt(this,e,!0))},fromEntrySeq:function(){return new Lt(this)},get:function(e,t){return this.find(function(t,n){return de(n,e)},void 0,t)},getIn:function(e,t){for(var n,r=this,o=rn(e);!(n=o.next()).done;){var i=n.value;if((r=r&&r.get?r.get(i,y):y)===y)return t}return r},groupBy:function(e,t){return function(e,t,n){var r=s(e),o=(l(e)?Tt():Ue()).asMutable();e.__iterate(function(i,a){o.update(t.call(n,i,a,e),function(e){return(e=e||[]).push(r?[a,i]:i),e})});var i=Qt(e);return o.map(function(t){return Gt(e,i(t))})}(this,e,t)},has:function(e){return this.get(e,y)!==y},hasIn:function(e){return this.getIn(e,y)!==y},isSubset:function(e){return e="function"==typeof e.includes?e:n(e),this.every(function(t){return e.includes(t)})},isSuperset:function(e){return(e="function"==typeof e.isSubset?e:n(e)).isSubset(this)},keyOf:function(e){return this.findKey(function(t){return de(t,e)})},keySeq:function(){return this.toSeq().map(Mn).toIndexedSeq()},last:function(){return this.toSeq().reverse().first()},lastKeyOf:function(e){return this.toKeyedSeq().reverse().keyOf(e)},max:function(e){return Kt(this,e)},maxBy:function(e,t){return Kt(this,t,e)},min:function(e){return Kt(this,e?Dn(e):qn)},minBy:function(e,t){return Kt(this,t?Dn(t):qn,e)},rest:function(){return this.slice(1)},skip:function(e){return this.slice(Math.max(0,e))},skipLast:function(e){return Gt(this,this.toSeq().reverse().skip(e).reverse())},skipWhile:function(e,t){return Gt(this,Vt(this,e,t,!0))},skipUntil:function(e,t){return this.skipWhile(Rn(e),t)},sortBy:function(e,t){return Gt(this,Jt(this,t,e))},take:function(e){return this.slice(0,Math.max(0,e))},takeLast:function(e){return Gt(this,this.toSeq().reverse().take(e).reverse())},takeWhile:function(e,t){return Gt(this,function(e,t,n){var r=en(e);return r.__iterateUncached=function(r,o){var i=this;if(o)return this.cacheResult().__iterate(r,o);var a=0;return e.__iterate(function(e,o,s){return t.call(n,e,o,s)&&++a&&r(e,o,i)}),a},r.__iteratorUncached=function(r,o){var i=this;if(o)return this.cacheResult().__iterator(r,o);var a=e.__iterator(N,o),s=!0;return new U(function(){if(!s)return{value:void 0,done:!0};var e=a.next();if(e.done)return e;var o=e.value,u=o[0],c=o[1];return t.call(n,c,u,i)?r===N?e:q(r,u,c,e):(s=!1,{value:void 0,done:!0})})},r}(this,e,t))},takeUntil:function(e,t){return this.takeWhile(Rn(e),t)},valueSeq:function(){return this.toIndexedSeq()},hashCode:function(){return this.__hash||(this.__hash=function(e){if(e.size===1/0)return 0;var t=l(e),n=s(e),r=t?1:0;return function(e,t){return t=Ee(t,3432918353),t=Ee(t<<15|t>>>-15,461845907),t=Ee(t<<13|t>>>-13,5),t=Ee((t=(t+3864292196|0)^e)^t>>>16,2246822507),t=Se((t=Ee(t^t>>>13,3266489909))^t>>>16)}(e.__iterate(n?t?function(e,t){r=31*r+Fn(Ce(e),Ce(t))|0}:function(e,t){r=r+Fn(Ce(e),Ce(t))|0}:t?function(e){r=31*r+Ce(e)|0}:function(e){r=r+Ce(e)|0}),r)}(this))}});var Pn=n.prototype;Pn[p]=!0,Pn[L]=Pn.values,Pn.__toJS=Pn.toArray,Pn.__toStringMapper=Ln,Pn.inspect=Pn.toSource=function(){return this.toString()},Pn.chain=Pn.flatMap,Pn.contains=Pn.includes,jn(r,{flip:function(){return Gt(this,Ut(this))},mapEntries:function(e,t){var n=this,r=0;return Gt(this,this.toSeq().map(function(o,i){return e.call(t,[i,o],r++,n)}).fromEntrySeq())},mapKeys:function(e,t){var n=this;return Gt(this,this.toSeq().flip().map(function(r,o){return e.call(t,r,o,n)}).flip())}});var In=r.prototype;function Mn(e,t){return t}function Nn(e,t){return[t,e]}function Rn(e){return function(){return!e.apply(this,arguments)}}function Dn(e){return function(){return-e.apply(this,arguments)}}function Ln(e){return"string"==typeof e?JSON.stringify(e):String(e)}function Un(){return S(arguments)}function qn(e,t){return et?-1:0}function Fn(e,t){return e^t+2654435769+(e<<6)+(e>>2)|0}return In[f]=!0,In[L]=Pn.entries,In.__toJS=Pn.toObject,In.__toStringMapper=function(e,t){return JSON.stringify(t)+": "+Ln(e)},jn(o,{toKeyedSeq:function(){return new Nt(this,!1)},filter:function(e,t){return Gt(this,Bt(this,e,t,!1))},findIndex:function(e,t){var n=this.findEntry(e,t);return n?n[0]:-1},indexOf:function(e){var t=this.keyOf(e);return void 0===t?-1:t},lastIndexOf:function(e){var t=this.lastKeyOf(e);return void 0===t?-1:t},reverse:function(){return Gt(this,Ft(this,!1))},slice:function(e,t){return Gt(this,zt(this,e,t,!1))},splice:function(e,t){var n=arguments.length;if(t=Math.max(0|t,0),0===n||2===n&&!t)return this;e=T(e,e<0?this.count():this.size);var r=this.slice(0,e);return Gt(this,1===n?r:r.concat(S(arguments,2),this.slice(e+t)))},findLastIndex:function(e,t){var n=this.findLastEntry(e,t);return n?n[0]:-1},first:function(){return this.get(0)},flatten:function(e){return Gt(this,Wt(this,e,!1))},get:function(e,t){return(e=k(this,e))<0||this.size===1/0||void 0!==this.size&&e>this.size?t:this.find(function(t,n){return n===e},void 0,t)},has:function(e){return(e=k(this,e))>=0&&(void 0!==this.size?this.size===1/0||e5e3)return e.textContent;return function(e){for(var n,r,o,i,a,s=e.textContent,u=0,c=s[0],l=1,p=e.innerHTML="",f=0;r=n,n=f<7&&"\\"==n?1:l;){if(l=c,c=s[++u],i=p.length>1,!l||f>8&&"\n"==l||[/\S/.test(l),1,1,!/[$\w]/.test(l),("/"==n||"\n"==n)&&i,'"'==n&&i,"'"==n&&i,s[u-4]+r+n=="--\x3e",r+n=="*/"][f])for(p&&(e.appendChild(a=t.createElement("span")).setAttribute("style",["color: #555; font-weight: bold;","","","color: #555;",""][f?f<3?2:f>6?4:f>3?3:+/^(a(bstract|lias|nd|rguments|rray|s(m|sert)?|uto)|b(ase|egin|ool(ean)?|reak|yte)|c(ase|atch|har|hecked|lass|lone|ompl|onst|ontinue)|de(bugger|cimal|clare|f(ault|er)?|init|l(egate|ete)?)|do|double|e(cho|ls?if|lse(if)?|nd|nsure|num|vent|x(cept|ec|p(licit|ort)|te(nds|nsion|rn)))|f(allthrough|alse|inal(ly)?|ixed|loat|or(each)?|riend|rom|unc(tion)?)|global|goto|guard|i(f|mp(lements|licit|ort)|n(it|clude(_once)?|line|out|stanceof|t(erface|ernal)?)?|s)|l(ambda|et|ock|ong)|m(icrolight|odule|utable)|NaN|n(amespace|ative|ext|ew|il|ot|ull)|o(bject|perator|r|ut|verride)|p(ackage|arams|rivate|rotected|rotocol|ublic)|r(aise|e(adonly|do|f|gister|peat|quire(_once)?|scue|strict|try|turn))|s(byte|ealed|elf|hort|igned|izeof|tatic|tring|truct|ubscript|uper|ynchronized|witch)|t(emplate|hen|his|hrows?|ransient|rue|ry|ype(alias|def|id|name|of))|u(n(checked|def(ined)?|ion|less|signed|til)|se|sing)|v(ar|irtual|oid|olatile)|w(char_t|hen|here|hile|ith)|xor|yield)$/.test(p):0]),a.appendChild(t.createTextNode(p))),o=f&&f<7?f:o,p="",f=11;![1,/[\/{}[(\-+*=<>:;|\\.,?!&@~]/.test(l),/[\])]/.test(l),/[$\w]/.test(l),"/"==l&&o<2&&"<"!=n,'"'==l,"'"==l,l+c+s[u+1]+s[u+2]=="\x3c!--",l+c=="/*",l+c=="//","#"==l][--f];);p+=l}}(e)}function Q(e){var t;if([/filename\*=[^']+'\w*'"([^"]+)";?/i,/filename\*=[^']+'\w*'([^;]+);?/i,/filename="([^;]*);?"/i,/filename=([^;]*);?/i].some(function(n){return null!==(t=n.exec(e))}),null!==t&&t.length>1)try{return decodeURIComponent(t[1])}catch(e){console.error(e)}return null}function ee(e){return t=e.replace(/\.[^.\/]*$/,""),b()(g()(t));var t}var te=function(e,t){if(e>t)return"Value must be less than Maximum"},ne=function(e,t){if(et)return"Value must be less than MaxLength"},pe=function(e,t){if(e.length2&&void 0!==arguments[2]?arguments[2]:{},r=n.isOAS3,o=void 0!==r&&r,i=n.bypassRequiredCheck,a=void 0!==i&&i,s=[],u=e.get("required"),c=Object(P.a)(e,{isOAS3:o}),p=c.schema,h=c.parameterContentMediaType;if(!p)return s;var m=p.get("required"),v=p.get("maximum"),g=p.get("minimum"),y=p.get("type"),b=p.get("format"),_=p.get("maxLength"),w=p.get("minLength"),x=p.get("pattern");if(y&&(u||m||t)){var E="string"===y&&t,S="array"===y&&l()(t)&&t.length,C="array"===y&&d.a.List.isList(t)&&t.count(),k="array"===y&&"string"==typeof t&&t,O="file"===y&&t instanceof A.a.File,T="boolean"===y&&(t||!1===t),j="number"===y&&(t||0===t),I="integer"===y&&(t||0===t),M="object"===y&&"object"===f()(t)&&null!==t,N="object"===y&&"string"==typeof t&&t,R=[E,S,C,k,O,T,j,I,M,N],D=R.some(function(e){return!!e});if((u||m)&&!D&&!a)return s.push("Required field is not provided"),s;if("object"===y&&"string"==typeof t&&(null===h||"application/json"===h))try{JSON.parse(t)}catch(e){return s.push("Parameter string value must be valid JSON"),s}if(x){var L=fe(t,x);L&&s.push(L)}if(_||0===_){var U=le(t,_);U&&s.push(U)}if(w){var q=pe(t,w);q&&s.push(q)}if(v||0===v){var F=te(t,v);F&&s.push(F)}if(g||0===g){var B=ne(t,g);B&&s.push(B)}if("string"===y){var z;if(!(z="date-time"===b?ue(t):"uuid"===b?ce(t):se(t)))return s;s.push(z)}else if("boolean"===y){var V=ae(t);if(!V)return s;s.push(V)}else if("number"===y){var H=re(t);if(!H)return s;s.push(H)}else if("integer"===y){var W=oe(t);if(!W)return s;s.push(W)}else if("array"===y){var J;if(!C||!t.count())return s;J=p.getIn(["items","type"]),t.forEach(function(e,t){var n;"number"===J?n=re(e):"integer"===J?n=oe(e):"string"===J&&(n=se(e)),n&&s.push({index:t,error:n})})}else if("file"===y){var K=ie(t);if(!K)return s;s.push(K)}}return s},de=function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"",n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{};if(/xml/.test(t)){if(!e.xml||!e.xml.name){if(e.xml=e.xml||{},!e.$$ref)return e.type||e.items||e.properties||e.additionalProperties?'\n\x3c!-- XML example cannot be generated; root element name is undefined --\x3e':null;var r=e.$$ref.match(/\S*\/(\S+)$/);e.xml.name=r[1]}return Object(k.memoizedCreateXMLExample)(e,n)}var i=Object(k.memoizedSampleFromSchema)(e,n);return"object"===f()(i)?o()(i,null,2):i},me=function(){var e={},t=A.a.location.search;if(!t)return{};if(""!=t){var n=t.substr(1).split("&");for(var r in n)n.hasOwnProperty(r)&&(r=n[r].split("="),e[decodeURIComponent(r[0])]=r[1]&&decodeURIComponent(r[1])||"")}return e},ve=function(t){return(t instanceof e?t:new e(t.toString(),"utf-8")).toString("base64")},ge={operationsSorter:{alpha:function(e,t){return e.get("path").localeCompare(t.get("path"))},method:function(e,t){return e.get("method").localeCompare(t.get("method"))}},tagsSorter:{alpha:function(e,t){return e.localeCompare(t)}}},ye=function(e){var t=[];for(var n in e){var r=e[n];void 0!==r&&""!==r&&t.push([n,"=",encodeURIComponent(r).replace(/%20/g,"+")].join(""))}return t.join("&")},be=function(e,t,n){return!!E()(n,function(n){return C()(e[n],t[n])})};function _e(e){return"string"!=typeof e||""===e?"":Object(m.sanitizeUrl)(e)}function we(e){if(!d.a.OrderedMap.isOrderedMap(e))return null;if(!e.size)return null;var t=e.find(function(e,t){return t.startsWith("2")&&u()(e.get("content")||{}).length>0}),n=e.get("default")||d.a.OrderedMap(),r=(n.get("content")||d.a.OrderedMap()).keySeq().toJS().length?n:null;return t||r}var xe=function(e){return"string"==typeof e||e instanceof String?e.trim().replace(/\s/g,"%20"):""},Ee=function(e){return j()(xe(e).replace(/%20/g,"_"))},Se=function(e){return e.filter(function(e,t){return/^x-/.test(t)})},Ce=function(e){return e.filter(function(e,t){return/^pattern|maxLength|minLength|maximum|minimum/.test(t)})};function ke(e,t){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:function(){return!0};if("object"!==f()(e)||l()(e)||null===e||!t)return e;var r=a()({},e);return u()(r).forEach(function(e){e===t&&n(r[e],e)?delete r[e]:r[e]=ke(r[e],t,n)}),r}function Oe(e){if("string"==typeof e)return e;if(e&&e.toJS&&(e=e.toJS()),"object"===f()(e)&&null!==e)try{return o()(e,null,2)}catch(t){return String(e)}return null==e?"":e.toString()}function Ae(e){return"number"==typeof e?e.toString():e}function Te(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},n=t.returnAll,r=void 0!==n&&n,o=t.allowHashes,i=void 0===o||o;if(!d.a.Map.isMap(e))throw new Error("paramToIdentifier: received a non-Im.Map parameter as input");var a=e.get("name"),s=e.get("in"),u=[];return e&&e.hashCode&&s&&a&&i&&u.push("".concat(s,".").concat(a,".hash-").concat(e.hashCode())),s&&a&&u.push("".concat(s,".").concat(a)),u.push(a),r?u:u[0]||""}function je(e,t){return Te(e,{returnAll:!0}).map(function(e){return t[e]}).filter(function(e){return void 0!==e})[0]}function Pe(){return Me(M()(32).toString("base64"))}function Ie(e){return Me(R()("sha256").update(e).digest("base64"))}function Me(e){return e.replace(/\+/g,"-").replace(/\//g,"_").replace(/=/g,"")}}).call(this,n(64).Buffer)},function(e,t){e.exports=function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}},function(e,t,n){var r=n(54);function o(e,t){for(var n=0;n1?t-1:0),o=1;o2?n-2:0),i=2;i>",i={listOf:function(e){return c(e,"List",r.List.isList)},mapOf:function(e,t){return l(e,t,"Map",r.Map.isMap)},orderedMapOf:function(e,t){return l(e,t,"OrderedMap",r.OrderedMap.isOrderedMap)},setOf:function(e){return c(e,"Set",r.Set.isSet)},orderedSetOf:function(e){return c(e,"OrderedSet",r.OrderedSet.isOrderedSet)},stackOf:function(e){return c(e,"Stack",r.Stack.isStack)},iterableOf:function(e){return c(e,"Iterable",r.Iterable.isIterable)},recordOf:function(e){return s(function(t,n,o,i,s){for(var u=arguments.length,c=Array(u>5?u-5:0),l=5;l6?u-6:0),l=6;l5?c-5:0),p=5;p5?i-5:0),s=5;s key("+l[p]+")"].concat(a));if(h instanceof Error)return h}})).apply(void 0,i);var u})}function p(e){var t=void 0===arguments[1]?"Iterable":arguments[1],n=void 0===arguments[2]?r.Iterable.isIterable:arguments[2];return s(function(r,o,i,s,u){for(var c=arguments.length,l=Array(c>5?c-5:0),p=5;p4)}function u(e){var t=e.get("swagger");return"string"==typeof t&&t.startsWith("2.0")}function c(e){return function(t,n){return function(r){return n&&n.specSelectors&&n.specSelectors.specJson?s(n.specSelectors.specJson())?a.a.createElement(e,o()({},r,n,{Ori:t})):a.a.createElement(t,r):(console.warn("OAS3 wrapper: couldn't get spec"),null)}}}},function(e,t,n){"use strict";
+/*
+object-assign
+(c) Sindre Sorhus
+@license MIT
+*/var r=Object.getOwnPropertySymbols,o=Object.prototype.hasOwnProperty,i=Object.prototype.propertyIsEnumerable;function a(e){if(null==e)throw new TypeError("Object.assign cannot be called with null or undefined");return Object(e)}e.exports=function(){try{if(!Object.assign)return!1;var e=new String("abc");if(e[5]="de","5"===Object.getOwnPropertyNames(e)[0])return!1;for(var t={},n=0;n<10;n++)t["_"+String.fromCharCode(n)]=n;if("0123456789"!==Object.getOwnPropertyNames(t).map(function(e){return t[e]}).join(""))return!1;var r={};return"abcdefghijklmnopqrst".split("").forEach(function(e){r[e]=e}),"abcdefghijklmnopqrst"===Object.keys(Object.assign({},r)).join("")}catch(e){return!1}}()?Object.assign:function(e,t){for(var n,s,u=a(e),c=1;c0){var o=n.map(function(e){return console.error(e),e.line=e.fullPath?g(y,e.fullPath):null,e.path=e.fullPath?e.fullPath.join("."):null,e.level="error",e.type="thrown",e.source="resolver",A()(e,"message",{enumerable:!0,value:e.message}),e});i.newThrownErrBatch(o)}return r.updateResolved(t)})}},_e=[],we=V()(k()(S.a.mark(function e(){var t,n,r,o,i,a,s,u,c,l,p,f,h,d,m,v,g;return S.a.wrap(function(e){for(;;)switch(e.prev=e.next){case 0:if(t=_e.system){e.next=4;break}return console.error("debResolveSubtrees: don't have a system to operate on, aborting."),e.abrupt("return");case 4:if(n=t.errActions,r=t.errSelectors,o=t.fn,i=o.resolveSubtree,a=o.AST,s=void 0===a?{}:a,u=t.specSelectors,c=t.specActions,i){e.next=8;break}return console.error("Error: Swagger-Client did not provide a `resolveSubtree` method, doing nothing."),e.abrupt("return");case 8:return l=s.getLineNumberForPath?s.getLineNumberForPath:function(){},p=u.specStr(),f=t.getConfigs(),h=f.modelPropertyMacro,d=f.parameterMacro,m=f.requestInterceptor,v=f.responseInterceptor,e.prev=11,e.next=14,_e.reduce(function(){var e=k()(S.a.mark(function e(t,o){var a,s,c,f,g,y,b;return S.a.wrap(function(e){for(;;)switch(e.prev=e.next){case 0:return e.next=2,t;case 2:return a=e.sent,s=a.resultMap,c=a.specWithCurrentSubtrees,e.next=7,i(c,o,{baseDoc:u.url(),modelPropertyMacro:h,parameterMacro:d,requestInterceptor:m,responseInterceptor:v});case 7:return f=e.sent,g=f.errors,y=f.spec,r.allErrors().size&&n.clearBy(function(e){return"thrown"!==e.get("type")||"resolver"!==e.get("source")||!e.get("fullPath").every(function(e,t){return e===o[t]||void 0===o[t]})}),j()(g)&&g.length>0&&(b=g.map(function(e){return e.line=e.fullPath?l(p,e.fullPath):null,e.path=e.fullPath?e.fullPath.join("."):null,e.level="error",e.type="thrown",e.source="resolver",A()(e,"message",{enumerable:!0,value:e.message}),e}),n.newThrownErrBatch(b)),W()(s,o,y),W()(c,o,y),e.abrupt("return",{resultMap:s,specWithCurrentSubtrees:c});case 15:case"end":return e.stop()}},e)}));return function(t,n){return e.apply(this,arguments)}}(),x.a.resolve({resultMap:(u.specResolvedSubtree([])||Object(R.Map)()).toJS(),specWithCurrentSubtrees:u.specJson().toJS()}));case 14:g=e.sent,delete _e.system,_e=[],e.next=22;break;case 19:e.prev=19,e.t0=e.catch(11),console.error(e.t0);case 22:c.updateResolvedSubtree([],g.resultMap);case 23:case"end":return e.stop()}},e,null,[[11,19]])})),35),xe=function(e){return function(t){_e.map(function(e){return e.join("@@")}).indexOf(e.join("@@"))>-1||(_e.push(e),_e.system=t,we())}};function Ee(e,t,n,r,o){return{type:X,payload:{path:e,value:r,paramName:t,paramIn:n,isXml:o}}}function Se(e,t,n,r){return{type:X,payload:{path:e,param:t,value:n,isXml:r}}}var Ce=function(e,t){return{type:le,payload:{path:e,value:t}}},ke=function(){return{type:le,payload:{path:[],value:Object(R.Map)()}}},Oe=function(e,t){return{type:ee,payload:{pathMethod:e,isOAS3:t}}},Ae=function(e,t,n,r){return{type:Q,payload:{pathMethod:e,paramName:t,paramIn:n,includeEmptyValue:r}}};function Te(e){return{type:se,payload:{pathMethod:e}}}function je(e,t){return{type:ue,payload:{path:e,value:t,key:"consumes_value"}}}function Pe(e,t){return{type:ue,payload:{path:e,value:t,key:"produces_value"}}}var Ie=function(e,t,n){return{payload:{path:e,method:t,res:n},type:te}},Me=function(e,t,n){return{payload:{path:e,method:t,req:n},type:ne}},Ne=function(e,t,n){return{payload:{path:e,method:t,req:n},type:re}},Re=function(e){return{payload:e,type:oe}},De=function(e){return function(t){var n=t.fn,r=t.specActions,o=t.specSelectors,i=t.getConfigs,a=t.oas3Selectors,s=e.pathName,u=e.method,c=e.operation,l=i(),p=l.requestInterceptor,f=l.responseInterceptor,h=c.toJS();if(c&&c.get("parameters")&&c.get("parameters").filter(function(e){return e&&!0===e.get("allowEmptyValue")}).forEach(function(t){if(o.parameterInclusionSettingFor([s,u],t.get("name"),t.get("in"))){e.parameters=e.parameters||{};var n=Object(J.C)(t,e.parameters);(!n||n&&0===n.size)&&(e.parameters[t.get("name")]="")}}),e.contextUrl=L()(o.url()).toString(),h&&h.operationId?e.operationId=h.operationId:h&&s&&u&&(e.operationId=n.opId(h,s,u)),o.isOAS3()){var d="".concat(s,":").concat(u);e.server=a.selectedServer(d)||a.selectedServer();var m=a.serverVariables({server:e.server,namespace:d}).toJS(),g=a.serverVariables({server:e.server}).toJS();e.serverVariables=_()(m).length?m:g,e.requestContentType=a.requestContentType(s,u),e.responseContentType=a.responseContentType(s,u)||"*/*";var b=a.requestBodyValue(s,u);Object(J.t)(b)?e.requestBody=JSON.parse(b):b&&b.toJS?e.requestBody=b.toJS():e.requestBody=b}var w=y()({},e);w=n.buildRequest(w),r.setRequest(e.pathName,e.method,w);e.requestInterceptor=function(t){var n=p.apply(this,[t]),o=y()({},n);return r.setMutatedRequest(e.pathName,e.method,o),n},e.responseInterceptor=f;var x=v()();return n.execute(e).then(function(t){t.duration=v()()-x,r.setResponse(e.pathName,e.method,t)}).catch(function(t){console.error(t),r.setResponse(e.pathName,e.method,{error:!0,err:q()(t)})})}},Le=function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},t=e.path,n=e.method,r=d()(e,["path","method"]);return function(e){var o=e.fn.fetch,i=e.specSelectors,a=e.specActions,s=i.specJsonWithResolvedSubtrees().toJS(),u=i.operationScheme(t,n),c=i.contentTypeValues([t,n]).toJS(),l=c.requestContentType,p=c.responseContentType,f=/xml/i.test(l),h=i.parameterValues([t,n],f).toJS();return a.executeRequest(Y({},r,{fetch:o,spec:s,pathName:t,method:n,parameters:h,requestContentType:l,scheme:u,responseContentType:p}))}};function Ue(e,t){return{type:ie,payload:{path:e,method:t}}}function qe(e,t){return{type:ae,payload:{path:e,method:t}}}function Fe(e,t,n){return{type:pe,payload:{scheme:e,path:t,method:n}}}},function(e,t,n){var r=n(32),o=n(22),i=n(63),a=n(77),s=n(75),u=function(e,t,n){var c,l,p,f=e&u.F,h=e&u.G,d=e&u.S,m=e&u.P,v=e&u.B,g=e&u.W,y=h?o:o[t]||(o[t]={}),b=y.prototype,_=h?r:d?r[t]:(r[t]||{}).prototype;for(c in h&&(n=t),n)(l=!f&&_&&void 0!==_[c])&&s(y,c)||(p=l?_[c]:n[c],y[c]=h&&"function"!=typeof _[c]?n[c]:v&&l?i(p,r):g&&_[c]==p?function(e){var t=function(t,n,r){if(this instanceof e){switch(arguments.length){case 0:return new e;case 1:return new e(t);case 2:return new e(t,n)}return new e(t,n,r)}return e.apply(this,arguments)};return t.prototype=e.prototype,t}(p):m&&"function"==typeof p?i(Function.call,p):p,m&&((y.virtual||(y.virtual={}))[c]=p,e&u.R&&b&&!b[c]&&a(b,c,p)))};u.F=1,u.G=2,u.S=4,u.P=8,u.B=16,u.W=32,u.U=64,u.R=128,e.exports=u},function(e,t,n){"use strict";var r=n(138),o=["kind","resolve","construct","instanceOf","predicate","represent","defaultStyle","styleAliases"],i=["scalar","sequence","mapping"];e.exports=function(e,t){var n,a;if(t=t||{},Object.keys(t).forEach(function(t){if(-1===o.indexOf(t))throw new r('Unknown option "'+t+'" is met in definition of "'+e+'" YAML type.')}),this.tag=e,this.kind=t.kind||null,this.resolve=t.resolve||function(){return!0},this.construct=t.construct||function(e){return e},this.instanceOf=t.instanceOf||null,this.predicate=t.predicate||null,this.represent=t.represent||null,this.defaultStyle=t.defaultStyle||null,this.styleAliases=(n=t.styleAliases||null,a={},null!==n&&Object.keys(n).forEach(function(e){n[e].forEach(function(t){a[String(t)]=e})}),a),-1===i.indexOf(this.kind))throw new r('Unknown kind "'+this.kind+'" is specified for "'+e+'" YAML type.')}},function(e,t){var n=e.exports="undefined"!=typeof window&&window.Math==Math?window:"undefined"!=typeof self&&self.Math==Math?self:Function("return this")();"number"==typeof __g&&(__g=n)},function(e,t,n){var r=n(197)("wks"),o=n(199),i=n(41).Symbol,a="function"==typeof i;(e.exports=function(e){return r[e]||(r[e]=a&&i[e]||(a?i:o)("Symbol."+e))}).store=r},function(e,t,n){var r=n(214)("wks"),o=n(159),i=n(32).Symbol,a="function"==typeof i;(e.exports=function(e){return r[e]||(r[e]=a&&i[e]||(a?i:o)("Symbol."+e))}).store=r},function(e,t,n){var r=n(41),o=n(72),i=n(81),a=n(97),s=n(153),u=function(e,t,n){var c,l,p,f,h=e&u.F,d=e&u.G,m=e&u.S,v=e&u.P,g=e&u.B,y=d?r:m?r[t]||(r[t]={}):(r[t]||{}).prototype,b=d?o:o[t]||(o[t]={}),_=b.prototype||(b.prototype={});for(c in d&&(n=t),n)p=((l=!h&&y&&void 0!==y[c])?y:n)[c],f=g&&l?s(p,r):v&&"function"==typeof p?s(Function.call,p):p,y&&a(y,c,p,e&u.U),b[c]!=p&&i(b,c,f),v&&_[c]!=p&&(_[c]=p)};r.core=o,u.F=1,u.G=2,u.S=4,u.P=8,u.B=16,u.W=32,u.U=64,u.R=128,e.exports=u},function(e,t){var n;n=function(){return this}();try{n=n||new Function("return this")()}catch(e){"object"==typeof window&&(n=window)}e.exports=n},function(e,t){var n=Array.isArray;e.exports=n},function(e,t,n){"use strict";var r=!("undefined"==typeof window||!window.document||!window.document.createElement),o={canUseDOM:r,canUseWorkers:"undefined"!=typeof Worker,canUseEventListeners:r&&!(!window.addEventListener&&!window.attachEvent),canUseViewport:r&&!!window.screen,isInWorker:!r};e.exports=o},function(e,t,n){"use strict";var r=Object.prototype.hasOwnProperty;function o(e,t){return!!e&&r.call(e,t)}var i=/\\([\\!"#$%&'()*+,.\/:;<=>?@[\]^_`{|}~-])/g;function a(e){return!(e>=55296&&e<=57343)&&(!(e>=64976&&e<=65007)&&(65535!=(65535&e)&&65534!=(65535&e)&&(!(e>=0&&e<=8)&&(11!==e&&(!(e>=14&&e<=31)&&(!(e>=127&&e<=159)&&!(e>1114111)))))))}function s(e){if(e>65535){var t=55296+((e-=65536)>>10),n=56320+(1023&e);return String.fromCharCode(t,n)}return String.fromCharCode(e)}var u=/&([a-z#][a-z0-9]{1,31});/gi,c=/^#((?:x[a-f0-9]{1,8}|[0-9]{1,8}))/i,l=n(463);function p(e,t){var n=0;return o(l,t)?l[t]:35===t.charCodeAt(0)&&c.test(t)&&a(n="x"===t[1].toLowerCase()?parseInt(t.slice(2),16):parseInt(t.slice(1),10))?s(n):e}var f=/[&<>"]/,h=/[&<>"]/g,d={"&":"&","<":"<",">":">",'"':"""};function m(e){return d[e]}t.assign=function(e){return[].slice.call(arguments,1).forEach(function(t){if(t){if("object"!=typeof t)throw new TypeError(t+"must be object");Object.keys(t).forEach(function(n){e[n]=t[n]})}}),e},t.isString=function(e){return"[object String]"===function(e){return Object.prototype.toString.call(e)}(e)},t.has=o,t.unescapeMd=function(e){return e.indexOf("\\")<0?e:e.replace(i,"$1")},t.isValidEntityCode=a,t.fromCodePoint=s,t.replaceEntities=function(e){return e.indexOf("&")<0?e:e.replace(u,p)},t.escapeHtml=function(e){return f.test(e)?e.replace(h,m):e}},function(e,t,n){var r=n(55),o=n(771);e.exports=function(e,t){if(null==e)return{};var n,i,a=o(e,t);if(r){var s=r(e);for(i=0;i=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}},function(e,t){var n=e.exports="undefined"!=typeof window&&window.Math==Math?window:"undefined"!=typeof self&&self.Math==Math?self:Function("return this")();"number"==typeof __g&&(__g=n)},function(e,t,n){var r=n(35),o=n(99),i=n(73),a=/"/g,s=function(e,t,n,r){var o=String(i(e)),s="<"+t;return""!==n&&(s+=" "+n+'="'+String(r).replace(a,""")+'"'),s+">"+o+""};e.exports=function(e,t){var n={};n[e]=t(s),r(r.P+r.F*o(function(){var t=""[e]('"');return t!==t.toLowerCase()||t.split('"').length>3}),"String",n)}},function(e,t){e.exports=function(e){return"object"==typeof e?null!==e:"function"==typeof e}},function(e,t,n){"use strict";n.r(t),n.d(t,"NEW_THROWN_ERR",function(){return i}),n.d(t,"NEW_THROWN_ERR_BATCH",function(){return a}),n.d(t,"NEW_SPEC_ERR",function(){return s}),n.d(t,"NEW_SPEC_ERR_BATCH",function(){return u}),n.d(t,"NEW_AUTH_ERR",function(){return c}),n.d(t,"CLEAR",function(){return l}),n.d(t,"CLEAR_BY",function(){return p}),n.d(t,"newThrownErr",function(){return f}),n.d(t,"newThrownErrBatch",function(){return h}),n.d(t,"newSpecErr",function(){return d}),n.d(t,"newSpecErrBatch",function(){return m}),n.d(t,"newAuthErr",function(){return v}),n.d(t,"clear",function(){return g}),n.d(t,"clearBy",function(){return y});var r=n(119),o=n.n(r),i="err_new_thrown_err",a="err_new_thrown_err_batch",s="err_new_spec_err",u="err_new_spec_err_batch",c="err_new_auth_err",l="err_clear",p="err_clear_by";function f(e){return{type:i,payload:o()(e)}}function h(e){return{type:a,payload:e}}function d(e){return{type:s,payload:e}}function m(e){return{type:u,payload:e}}function v(e){return{type:c,payload:e}}function g(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};return{type:l,payload:e}}function y(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:function(){return!0};return{type:p,payload:e}}},function(e,t,n){var r=n(98);e.exports=function(e){if(!r(e))throw TypeError(e+" is not an object!");return e}},function(e,t,n){var r=n(43);e.exports=function(e){if(!r(e))throw TypeError(e+" is not an object!");return e}},function(e,t){"function"==typeof Object.create?e.exports=function(e,t){e.super_=t,e.prototype=Object.create(t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}})}:e.exports=function(e,t){e.super_=t;var n=function(){};n.prototype=t.prototype,e.prototype=new n,e.prototype.constructor=e}},function(e,t,n){var r=n(64),o=r.Buffer;function i(e,t){for(var n in e)t[n]=e[n]}function a(e,t,n){return o(e,t,n)}o.from&&o.alloc&&o.allocUnsafe&&o.allocUnsafeSlow?e.exports=r:(i(r,t),t.Buffer=a),i(o,a),a.from=function(e,t,n){if("number"==typeof e)throw new TypeError("Argument must not be a number");return o(e,t,n)},a.alloc=function(e,t,n){if("number"!=typeof e)throw new TypeError("Argument must be a number");var r=o(e);return void 0!==t?"string"==typeof n?r.fill(t,n):r.fill(t):r.fill(0),r},a.allocUnsafe=function(e){if("number"!=typeof e)throw new TypeError("Argument must be a number");return o(e)},a.allocUnsafeSlow=function(e){if("number"!=typeof e)throw new TypeError("Argument must be a number");return r.SlowBuffer(e)}},function(e,t,n){var r=n(46),o=n(349),i=n(218),a=Object.defineProperty;t.f=n(50)?Object.defineProperty:function(e,t,n){if(r(e),t=i(t,!0),r(n),o)try{return a(e,t,n)}catch(e){}if("get"in n||"set"in n)throw TypeError("Accessors not supported!");return"value"in n&&(e[t]=n.value),e}},function(e,t,n){e.exports=!n(82)(function(){return 7!=Object.defineProperty({},"a",{get:function(){return 7}}).a})},function(e,t,n){var r=n(366),o="object"==typeof self&&self&&self.Object===Object&&self,i=r||o||Function("return this")();e.exports=i},function(e,t){e.exports=function(e){var t=typeof e;return null!=e&&("object"==t||"function"==t)}},function(e,t,n){"use strict";e.exports={debugTool:null}},function(e,t,n){e.exports=n(573)},function(e,t,n){e.exports=n(770)},function(e,t,n){e.exports=function(e){var t={};function n(r){if(t[r])return t[r].exports;var o=t[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}return n.m=e,n.c=t,n.d=function(e,t,r){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)n.d(r,o,function(t){return e[t]}.bind(null,o));return r},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="",n(n.s=45)}([function(e,t){e.exports=n(17)},function(e,t){e.exports=n(14)},function(e,t){e.exports=n(26)},function(e,t){e.exports=n(16)},function(e,t){e.exports=n(123)},function(e,t){e.exports=n(60)},function(e,t){e.exports=n(61)},function(e,t){e.exports=n(55)},function(e,t){e.exports=n(2)},function(e,t){e.exports=n(54)},function(e,t){e.exports=n(94)},function(e,t){e.exports=n(28)},function(e,t){e.exports=n(930)},function(e,t){e.exports=n(12)},function(e,t){e.exports=n(192)},function(e,t){e.exports=n(936)},function(e,t){e.exports=n(93)},function(e,t){e.exports=n(193)},function(e,t){e.exports=n(939)},function(e,t){e.exports=n(943)},function(e,t){e.exports=n(944)},function(e,t){e.exports=n(92)},function(e,t){e.exports=n(13)},function(e,t){e.exports=n(146)},function(e,t){e.exports=n(4)},function(e,t){e.exports=n(5)},function(e,t){e.exports=n(946)},function(e,t){e.exports=n(421)},function(e,t){e.exports=n(949)},function(e,t){e.exports=n(52)},function(e,t){e.exports=n(64)},function(e,t){e.exports=n(283)},function(e,t){e.exports=n(272)},function(e,t){e.exports=n(950)},function(e,t){e.exports=n(145)},function(e,t){e.exports=n(951)},function(e,t){e.exports=n(959)},function(e,t){e.exports=n(960)},function(e,t){e.exports=n(961)},function(e,t){e.exports=n(40)},function(e,t){e.exports=n(264)},function(e,t){e.exports=n(37)},function(e,t){e.exports=n(964)},function(e,t){e.exports=n(965)},function(e,t){e.exports=n(966)},function(e,t,n){e.exports=n(50)},function(e,t){e.exports=n(967)},function(e,t){e.exports=n(968)},function(e,t){e.exports=n(969)},function(e,t){e.exports=n(970)},function(e,t,n){"use strict";n.r(t);var r={};n.r(r),n.d(r,"path",function(){return mn}),n.d(r,"query",function(){return vn}),n.d(r,"header",function(){return yn}),n.d(r,"cookie",function(){return bn});var o=n(9),i=n.n(o),a=n(10),s=n.n(a),u=n(5),c=n.n(u),l=n(6),p=n.n(l),f=n(7),h=n.n(f),d=n(0),m=n.n(d),v=n(8),g=n.n(v),y=(n(46),n(15)),b=n.n(y),_=n(20),w=n.n(_),x=n(12),E=n.n(x),S=n(4),C=n.n(S),k=n(22),O=n.n(k),A=n(11),T=n.n(A),j=n(2),P=n.n(j),I=n(1),M=n.n(I),N=n(17),R=n.n(N),D=(n(47),n(26)),L=n.n(D),U=n(23),q=n.n(U),F=n(31),B=n.n(F),z={serializeRes:J,mergeInQueryOrForm:Z};function V(e){return H.apply(this,arguments)}function H(){return(H=R()(C.a.mark(function e(t){var n,r,o,i,a,s=arguments;return C.a.wrap(function(e){for(;;)switch(e.prev=e.next){case 0:if(n=s.length>1&&void 0!==s[1]?s[1]:{},"object"===P()(t)&&(t=(n=t).url),n.headers=n.headers||{},z.mergeInQueryOrForm(n),n.headers&&m()(n.headers).forEach(function(e){var t=n.headers[e];"string"==typeof t&&(n.headers[e]=t.replace(/\n+/g," "))}),!n.requestInterceptor){e.next=12;break}return e.next=8,n.requestInterceptor(n);case 8:if(e.t0=e.sent,e.t0){e.next=11;break}e.t0=n;case 11:n=e.t0;case 12:return r=n.headers["content-type"]||n.headers["Content-Type"],/multipart\/form-data/i.test(r)&&(delete n.headers["content-type"],delete n.headers["Content-Type"]),e.prev=14,e.next=17,(n.userFetch||fetch)(n.url,n);case 17:return o=e.sent,e.next=20,z.serializeRes(o,t,n);case 20:if(o=e.sent,!n.responseInterceptor){e.next=28;break}return e.next=24,n.responseInterceptor(o);case 24:if(e.t1=e.sent,e.t1){e.next=27;break}e.t1=o;case 27:o=e.t1;case 28:e.next=38;break;case 30:if(e.prev=30,e.t2=e.catch(14),o){e.next=34;break}throw e.t2;case 34:throw(i=new Error(o.statusText)).statusCode=i.status=o.status,i.responseError=e.t2,i;case 38:if(o.ok){e.next=43;break}throw(a=new Error(o.statusText)).statusCode=a.status=o.status,a.response=o,a;case 43:return e.abrupt("return",o);case 44:case"end":return e.stop()}},e,null,[[14,30]])}))).apply(this,arguments)}var W=function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"";return/(json|xml|yaml|text)\b/.test(e)};function J(e,t){var n=(arguments.length>2&&void 0!==arguments[2]?arguments[2]:{}).loadSpec,r=void 0!==n&&n,o={ok:e.ok,url:e.url||t,status:e.status,statusText:e.statusText,headers:K(e.headers)},i=o.headers["content-type"],a=r||W(i);return(a?e.text:e.blob||e.buffer).call(e).then(function(e){if(o.text=e,o.data=e,a)try{var t=function(e,t){return t&&(0===t.indexOf("application/json")||t.indexOf("+json")>0)?JSON.parse(e):q.a.safeLoad(e)}(e,i);o.body=t,o.obj=t}catch(e){o.parseError=e}return o})}function K(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},t={};return"function"==typeof e.forEach?(e.forEach(function(e,n){void 0!==t[n]?(t[n]=M()(t[n])?t[n]:[t[n]],t[n].push(e)):t[n]=e}),t):t}function Y(e,t){return t||"undefined"==typeof navigator||(t=navigator),t&&"ReactNative"===t.product?!(!e||"object"!==P()(e)||"string"!=typeof e.uri):"undefined"!=typeof File?e instanceof File:null!==e&&"object"===P()(e)&&"function"==typeof e.pipe}function $(e,t){var n=e.collectionFormat,r=e.allowEmptyValue,o="object"===P()(e)?e.value:e;if(void 0===o&&r)return"";if(Y(o)||"boolean"==typeof o)return o;var i=encodeURIComponent;return t&&(i=B()(o)?function(e){return e}:function(e){return T()(e)}),"object"!==P()(o)||M()(o)?M()(o)?M()(o)&&!n?o.map(i).join(","):"multi"===n?o.map(i):o.map(i).join({csv:",",ssv:"%20",tsv:"%09",pipes:"|"}[n]):i(o):""}function G(e){var t=m()(e).reduce(function(t,n){var r,o=e[n],i=!!o.skipEncoding,a=i?n:encodeURIComponent(n),s=(r=o)&&"object"===P()(r)&&!M()(o);return t[a]=$(s?o:{value:o},i),t},{});return L.a.stringify(t,{encode:!1,indices:!1})||""}function Z(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},t=e.url,r=void 0===t?"":t,o=e.query,i=e.form;if(i){var a=m()(i).some(function(e){return Y(i[e].value)}),s=e.headers["content-type"]||e.headers["Content-Type"];if(a||/multipart\/form-data/i.test(s)){var u=n(48);e.body=new u,m()(i).forEach(function(t){e.body.append(t,$(i[t],!0))})}else e.body=G(i);delete e.form}if(o){var c=r.split("?"),l=O()(c,2),p=l[0],f=l[1],h="";if(f){var d=L.a.parse(f);m()(o).forEach(function(e){return delete d[e]}),h=L.a.stringify(d,{encode:!0})}var v=function(){for(var e=arguments.length,t=new Array(e),n=0;n0){var o=t(e,n[n.length-1],n);o&&(r=r.concat(o))}if(M()(e)){var i=e.map(function(e,r){return Ce(e,t,n.concat(r))});i&&(r=r.concat(i))}else if(Te(e)){var a=m()(e).map(function(r){return Ce(e[r],t,n.concat(r))});a&&(r=r.concat(a))}return r=Oe(r)}function ke(e){return M()(e)?e:[e]}function Oe(e){var t;return(t=[]).concat.apply(t,he()(e.map(function(e){return M()(e)?Oe(e):e})))}function Ae(e){return e.filter(function(e){return void 0!==e})}function Te(e){return e&&"object"===P()(e)}function je(e){return e&&"function"==typeof e}function Pe(e){if(Ne(e)){var t=e.op;return"add"===t||"remove"===t||"replace"===t}return!1}function Ie(e){return Pe(e)||Ne(e)&&"mutation"===e.type}function Me(e){return Ie(e)&&("add"===e.op||"replace"===e.op||"merge"===e.op||"mergeDeep"===e.op)}function Ne(e){return e&&"object"===P()(e)}function Re(e,t){try{return me.a.getValueByPointer(e,t)}catch(e){return console.error(e),{}}}var De=n(35),Le=n.n(De),Ue=n(36),qe=n(28),Fe=n.n(qe);function Be(e,t){function n(){Error.captureStackTrace?Error.captureStackTrace(this,this.constructor):this.stack=(new Error).stack;for(var e=arguments.length,n=new Array(e),r=0;r-1&&-1===We.indexOf(n)||Je.indexOf(r)>-1||Ke.some(function(e){return r.indexOf(e)>-1})}function $e(e,t){var n=e.split("#"),r=O()(n,2),o=r[0],i=r[1],a=E.a.resolve(o||"",t||"");return i?"".concat(a,"#").concat(i):a}var Ge="application/json, application/yaml",Ze=new RegExp("^([a-z]+://|//)","i"),Xe=Be("JSONRefError",function(e,t,n){this.originalError=n,ie()(this,t||{})}),Qe={},et=new Le.a,tt=[function(e){return"paths"===e[0]&&"responses"===e[3]&&"content"===e[5]&&"example"===e[7]},function(e){return"paths"===e[0]&&"requestBody"===e[3]&&"content"===e[4]&&"example"===e[6]}],nt={key:"$ref",plugin:function(e,t,n,r){var o=r.getInstance(),i=n.slice(0,-1);if(!Ye(i)&&(a=i,!tt.some(function(e){return e(a)}))){var a,s=r.getContext(n).baseDoc;if("string"!=typeof e)return new Xe("$ref: must be a string (JSON-Ref)",{$ref:e,baseDoc:s,fullPath:n});var u,c,l,p=st(e),f=p[0],h=p[1]||"";try{u=s||f?it(f,s):null}catch(t){return at(t,{pointer:h,$ref:e,basePath:u,fullPath:n})}if(function(e,t,n,r){var o=et.get(r);o||(o={},et.set(r,o));var i=function(e){if(0===e.length)return"";return"/".concat(e.map(ht).join("/"))}(n),a="".concat(t||"","#").concat(e),s=i.replace(/allOf\/\d+\/?/g,""),u=r.contextTree.get([]).baseDoc;if(t==u&&mt(s,e))return!0;var c="";if(n.some(function(e){return c="".concat(c,"/").concat(ht(e)),o[c]&&o[c].some(function(e){return mt(e,a)||mt(a,e)})}))return!0;o[s]=(o[s]||[]).concat(a)}(h,u,i,r)&&!o.useCircularStructures){var d=$e(e,u);return e===d?null:_e.replace(n,d)}if(null==u?(l=pt(h),void 0===(c=r.get(l))&&(c=new Xe("Could not resolve reference: ".concat(e),{pointer:h,$ref:e,baseDoc:s,fullPath:n}))):c=null!=(c=ut(u,h)).__value?c.__value:c.catch(function(t){throw at(t,{pointer:h,$ref:e,baseDoc:s,fullPath:n})}),c instanceof Error)return[_e.remove(n),c];var v=$e(e,u),g=_e.replace(i,c,{$$ref:v});if(u&&u!==s)return[g,_e.context(i,{baseDoc:u})];try{if(!function(e,t){var n=[e];return t.path.reduce(function(e,t){return n.push(e[t]),e[t]},e),function e(t){return _e.isObject(t)&&(n.indexOf(t)>=0||m()(t).some(function(n){return e(t[n])}))}(t.value)}(r.state,g)||o.useCircularStructures)return g}catch(e){return null}}}},rt=ie()(nt,{docCache:Qe,absoluteify:it,clearCache:function(e){void 0!==e?delete Qe[e]:m()(Qe).forEach(function(e){delete Qe[e]})},JSONRefError:Xe,wrapError:at,getDoc:ct,split:st,extractFromDoc:ut,fetchJSON:function(e){return Object(Ue.fetch)(e,{headers:{Accept:Ge},loadSpec:!0}).then(function(e){return e.text()}).then(function(e){return q.a.safeLoad(e)})},extract:lt,jsonPointerToArray:pt,unescapeJsonPointerToken:ft}),ot=rt;function it(e,t){if(!Ze.test(e)){if(!t)throw new Xe("Tried to resolve a relative URL, without having a basePath. path: '".concat(e,"' basePath: '").concat(t,"'"));return E.a.resolve(t,e)}return e}function at(e,t){var n;return n=e&&e.response&&e.response.body?"".concat(e.response.body.code," ").concat(e.response.body.message):e.message,new Xe("Could not resolve reference: ".concat(n),t,e)}function st(e){return(e+"").split("#")}function ut(e,t){var n=Qe[e];if(n&&!_e.isPromise(n))try{var r=lt(t,n);return ie()(Q.a.resolve(r),{__value:r})}catch(e){return Q.a.reject(e)}return ct(e).then(function(e){return lt(t,e)})}function ct(e){var t=Qe[e];return t?_e.isPromise(t)?t:Q.a.resolve(t):(Qe[e]=rt.fetchJSON(e).then(function(t){return Qe[e]=t,t}),Qe[e])}function lt(e,t){var n=pt(e);if(n.length<1)return t;var r=_e.getIn(t,n);if(void 0===r)throw new Xe("Could not resolve pointer: ".concat(e," does not exist in document"),{pointer:e});return r}function pt(e){if("string"!=typeof e)throw new TypeError("Expected a string, got a ".concat(P()(e)));return"/"===e[0]&&(e=e.substr(1)),""===e?[]:e.split("/").map(ft)}function ft(e){return"string"!=typeof e?e:Fe.a.unescape(e.replace(/~1/g,"/").replace(/~0/g,"~"))}function ht(e){return Fe.a.escape(e.replace(/~/g,"~0").replace(/\//g,"~1"))}var dt=function(e){return!e||"/"===e||"#"===e};function mt(e,t){if(dt(t))return!0;var n=e.charAt(t.length),r=t.slice(-1);return 0===e.indexOf(t)&&(!n||"/"===n||"#"===n)&&"#"!==r}var vt={key:"allOf",plugin:function(e,t,n,r,o){if(!o.meta||!o.meta.$$ref){var i=n.slice(0,-1);if(!Ye(i)){if(!M()(e)){var a=new TypeError("allOf must be an array");return a.fullPath=n,a}var s=!1,u=o.value;i.forEach(function(e){u&&(u=u[e])}),delete(u=ie()({},u)).allOf;var c=[];return c.push(r.replace(i,{})),e.forEach(function(e,t){if(!r.isObject(e)){if(s)return null;s=!0;var o=new TypeError("Elements in allOf must be objects");return o.fullPath=n,c.push(o)}c.push(r.mergeDeep(i,e));var a=function(e,t){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{},r=n.specmap,o=n.getBaseUrlForNodePath,i=void 0===o?function(e){return r.getContext([].concat(he()(t),he()(e))).baseDoc}:o,a=n.targetKeys,s=void 0===a?["$ref","$$ref"]:a,u=[];return Ve()(e).forEach(function(){if(s.indexOf(this.key)>-1){var e=this.path,n=t.concat(this.path),o=$e(this.node,i(e));u.push(r.replace(n,o))}}),u}(e,n.slice(0,-1),{getBaseUrlForNodePath:function(e){return r.getContext([].concat(he()(n),[t],he()(e))).baseDoc},specmap:r});c.push.apply(c,he()(a))}),c.push(r.mergeDeep(i,u)),u.$$ref||c.push(r.remove([].concat(i,"$$ref"))),c}}}},gt={key:"parameters",plugin:function(e,t,n,r,o){if(M()(e)&&e.length){var i=ie()([],e),a=n.slice(0,-1),s=ie()({},_e.getIn(r.spec,a));return e.forEach(function(e,t){try{i[t].default=r.parameterMacro(s,e)}catch(e){var o=new Error(e);return o.fullPath=n,o}}),_e.replace(n,i)}return _e.replace(n,e)}},yt={key:"properties",plugin:function(e,t,n,r){var o=ie()({},e);for(var i in e)try{o[i].default=r.modelPropertyMacro(o[i])}catch(e){var a=new Error(e);return a.fullPath=n,a}return _e.replace(n,o)}};function bt(e,t){var n=m()(e);if(h.a){var r=h()(e);t&&(r=r.filter(function(t){return p()(e,t).enumerable})),n.push.apply(n,r)}return n}var _t=function(){function e(t){se()(this,e),this.root=wt(t||{})}return ce()(e,[{key:"set",value:function(e,t){var n=this.getParent(e,!0);if(n){var r=e[e.length-1],o=n.children;o[r]?xt(o[r],t,n):o[r]=wt(t,n)}else xt(this.root,t,null)}},{key:"get",value:function(e){if((e=e||[]).length<1)return this.root.value;for(var t,n,r=this.root,o=0;o1?n-1:0),o=1;o1?n-1:0),o=1;o0})}},{key:"nextPromisedPatch",value:function(){if(this.promisedPatches.length>0)return Q.a.race(this.promisedPatches.map(function(e){return e.value}))}},{key:"getPluginHistory",value:function(e){var t=this.getPluginName(e);return this.pluginHistory[t]||[]}},{key:"getPluginRunCount",value:function(e){return this.getPluginHistory(e).length}},{key:"getPluginHistoryTip",value:function(e){var t=this.getPluginHistory(e);return t&&t[t.length-1]||{}}},{key:"getPluginMutationIndex",value:function(e){var t=this.getPluginHistoryTip(e).mutationIndex;return"number"!=typeof t?-1:t}},{key:"getPluginName",value:function(e){return e.pluginName}},{key:"updatePluginHistory",value:function(e,t){var n=this.getPluginName(e);(this.pluginHistory[n]=this.pluginHistory[n]||[]).push(t)}},{key:"updatePatches",value:function(e,t){var n=this;_e.normalizeArray(e).forEach(function(e){if(e instanceof Error)n.errors.push(e);else try{if(!_e.isObject(e))return void n.debug("updatePatches","Got a non-object patch",e);if(n.showDebug&&n.allPatches.push(e),_e.isPromise(e.value))return n.promisedPatches.push(e),void n.promisedPatchThen(e);if(_e.isContextPatch(e))return void n.setContext(e.path,e.value);if(_e.isMutation(e))return void n.updateMutations(e)}catch(e){console.error(e),n.errors.push(e)}})}},{key:"updateMutations",value:function(e){"object"===P()(e.value)&&!M()(e.value)&&this.allowMetaPatches&&(e.value=ie()({},e.value));var t=_e.applyPatch(this.state,e,{allowMetaPatches:this.allowMetaPatches});t&&(this.mutations.push(e),this.state=t)}},{key:"removePromisedPatch",value:function(e){var t=this.promisedPatches.indexOf(e);t<0?this.debug("Tried to remove a promisedPatch that isn't there!"):this.promisedPatches.splice(t,1)}},{key:"promisedPatchThen",value:function(e){var t=this;return e.value=e.value.then(function(n){var r=ie()({},e,{value:n});t.removePromisedPatch(e),t.updatePatches(r)}).catch(function(n){t.removePromisedPatch(e),t.updatePatches(n)})}},{key:"getMutations",value:function(e,t){return e=e||0,"number"!=typeof t&&(t=this.mutations.length),this.mutations.slice(e,t)}},{key:"getCurrentMutations",value:function(){return this.getMutationsForPlugin(this.getCurrentPlugin())}},{key:"getMutationsForPlugin",value:function(e){var t=this.getPluginMutationIndex(e);return this.getMutations(t+1)}},{key:"getCurrentPlugin",value:function(){return this.currentPlugin}},{key:"getPatchesOfType",value:function(e,t){return e.filter(t)}},{key:"getLib",value:function(){return this.libMethods}},{key:"_get",value:function(e){return _e.getIn(this.state,e)}},{key:"_getContext",value:function(e){return this.contextTree.get(e)}},{key:"setContext",value:function(e,t){return this.contextTree.set(e,t)}},{key:"_hasRun",value:function(e){return this.getPluginRunCount(this.getCurrentPlugin())>(e||0)}},{key:"_clone",value:function(e){return JSON.parse(T()(e))}},{key:"dispatch",value:function(){var e=this,t=this,n=this.nextPlugin();if(!n){var r=this.nextPromisedPatch();if(r)return r.then(function(){return e.dispatch()}).catch(function(){return e.dispatch()});var o={spec:this.state,errors:this.errors};return this.showDebug&&(o.patches=this.allPatches),Q.a.resolve(o)}if(t.pluginCount=t.pluginCount||{},t.pluginCount[n]=(t.pluginCount[n]||0)+1,t.pluginCount[n]>100)return Q.a.resolve({spec:t.state,errors:t.errors.concat(new Error("We've reached a hard limit of ".concat(100," plugin runs")))});if(n!==this.currentPlugin&&this.promisedPatches.length){var i=this.promisedPatches.map(function(e){return e.value});return Q.a.all(i.map(function(e){return e.then(Function,Function)})).then(function(){return e.dispatch()})}return function(){t.currentPlugin=n;var e=t.getCurrentMutations(),r=t.mutations.length-1;try{if(n.isGenerator){var o=!0,i=!1,s=void 0;try{for(var u,c=te()(n(e,t.getLib()));!(o=(u=c.next()).done);o=!0){a(u.value)}}catch(e){i=!0,s=e}finally{try{o||null==c.return||c.return()}finally{if(i)throw s}}}else{a(n(e,t.getLib()))}}catch(e){console.error(e),a([ie()(re()(e),{plugin:n})])}finally{t.updatePluginHistory(n,{mutationIndex:r})}return t.dispatch()}();function a(e){e&&(e=_e.fullyNormalizeArray(e),t.updatePatches(e,n))}}}]),e}();var St={refs:ot,allOf:vt,parameters:gt,properties:yt},Ct=n(29),kt=n.n(Ct),Ot=function(e){return String.prototype.toLowerCase.call(e)},At=function(e){return e.replace(/[^\w]/gi,"_")};function Tt(e){var t=e.openapi;return!!t&&w()(t,"3")}function jt(e,t){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:"",r=(arguments.length>3&&void 0!==arguments[3]?arguments[3]:{}).v2OperationIdCompatibilityMode;return e&&"object"===P()(e)?(e.operationId||"").replace(/\s/g,"").length?At(e.operationId):function(e,t){if((arguments.length>2&&void 0!==arguments[2]?arguments[2]:{}).v2OperationIdCompatibilityMode){var n="".concat(t.toLowerCase(),"_").concat(e).replace(/[\s!@#$%^&*()_+=[{\]};:<>|.\/?,\\'""-]/g,"_");return(n=n||"".concat(e.substring(1),"_").concat(t)).replace(/((_){2,})/g,"_").replace(/^(_)*/g,"").replace(/([_])*$/g,"")}return"".concat(Ot(t)).concat(At(e))}(t,n,{v2OperationIdCompatibilityMode:r}):null}function Pt(e,t){return"".concat(Ot(t),"-").concat(e)}function It(e,t){return e&&e.paths?function(e,t){return Mt(e,t,!0)||null}(e,function(e){var n=e.pathName,r=e.method,o=e.operation;if(!o||"object"!==P()(o))return!1;var i=o.operationId;return[jt(o,n,r),Pt(n,r),i].some(function(e){return e&&e===t})}):null}function Mt(e,t,n){if(!e||"object"!==P()(e)||!e.paths||"object"!==P()(e.paths))return null;var r=e.paths;for(var o in r)for(var i in r[o])if("PARAMETERS"!==i.toUpperCase()){var a=r[o][i];if(a&&"object"===P()(a)){var s={spec:e,pathName:o,method:i.toUpperCase(),operation:a},u=t(s);if(n&&u)return s}}}function Nt(e){var t=e.spec,n=t.paths,r={};if(!n||t.$$normalized)return e;for(var o in n){var i=n[o];if(kt()(i)){var a=i.parameters,s=function(e){var n=i[e];if(!kt()(n))return"continue";var s=jt(n,o,e);if(s){r[s]?r[s].push(n):r[s]=[n];var u=r[s];if(u.length>1)u.forEach(function(e,t){e.__originalOperationId=e.__originalOperationId||e.operationId,e.operationId="".concat(s).concat(t+1)});else if(void 0!==n.operationId){var c=u[0];c.__originalOperationId=c.__originalOperationId||n.operationId,c.operationId=s}}if("parameters"!==e){var l=[],p={};for(var f in t)"produces"!==f&&"consumes"!==f&&"security"!==f||(p[f]=t[f],l.push(p));if(a&&(p.parameters=a,l.push(p)),l.length)for(var h=0,d=l;h1&&void 0!==arguments[1]?arguments[1]:{},n=t.requestInterceptor,r=t.responseInterceptor,o=e.withCredentials?"include":"same-origin";return function(t){return e({url:t,loadSpec:!0,requestInterceptor:n,responseInterceptor:r,headers:{Accept:Ge},credentials:o}).then(function(e){return e.body})}}function Dt(e){var t=e.fetch,n=e.spec,r=e.url,o=e.mode,i=e.allowMetaPatches,a=void 0===i||i,s=e.pathDiscriminator,u=e.modelPropertyMacro,c=e.parameterMacro,l=e.requestInterceptor,p=e.responseInterceptor,f=e.skipNormalization,h=e.useCircularStructures,d=e.http,m=e.baseDoc;return m=m||r,d=t||d||V,n?v(n):Rt(d,{requestInterceptor:l,responseInterceptor:p})(m).then(v);function v(e){m&&(St.refs.docCache[m]=e),St.refs.fetchJSON=Rt(d,{requestInterceptor:l,responseInterceptor:p});var t,n=[St.refs];return"function"==typeof c&&n.push(St.parameters),"function"==typeof u&&n.push(St.properties),"strict"!==o&&n.push(St.allOf),(t={spec:e,context:{baseDoc:m},plugins:n,allowMetaPatches:a,pathDiscriminator:s,parameterMacro:c,modelPropertyMacro:u,useCircularStructures:h},new Et(t).dispatch()).then(f?function(){var e=R()(C.a.mark(function e(t){return C.a.wrap(function(e){for(;;)switch(e.prev=e.next){case 0:return e.abrupt("return",t);case 1:case"end":return e.stop()}},e)}));return function(t){return e.apply(this,arguments)}}():Nt)}}var Lt=n(16),Ut=n.n(Lt);function qt(e,t){var n=m()(e);if(h.a){var r=h()(e);t&&(r=r.filter(function(t){return p()(e,t).enumerable})),n.push.apply(n,r)}return n}function Ft(e){for(var t=1;t2&&void 0!==m[2]?m[2]:{},o=r.returnEntireTree,i=r.baseDoc,a=r.requestInterceptor,s=r.responseInterceptor,u=r.parameterMacro,c=r.modelPropertyMacro,l=r.useCircularStructures,p={pathDiscriminator:n,baseDoc:i,requestInterceptor:a,responseInterceptor:s,parameterMacro:u,modelPropertyMacro:c,useCircularStructures:l},f=Nt({spec:t}),h=f.spec,e.next=6,Dt(Ft({},p,{spec:h,allowMetaPatches:!0,skipNormalization:!0}));case 6:return d=e.sent,!o&&M()(n)&&n.length&&(d.spec=Ut()(d.spec,n)||null),e.abrupt("return",d);case 9:case"end":return e.stop()}},e)}))).apply(this,arguments)}var zt=n(38),Vt=n.n(zt);function Ht(e,t){var n=m()(e);if(h.a){var r=h()(e);t&&(r=r.filter(function(t){return p()(e,t).enumerable})),n.push.apply(n,r)}return n}function Wt(e){for(var t=1;t0&&void 0!==arguments[0]?arguments[0]:{};return function(t){var n=t.pathName,r=t.method,o=t.operationId;return function(t){var i=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};return e.execute(Wt({spec:e.spec},Vt()(e,"requestInterceptor","responseInterceptor","userFetch"),{pathName:n,method:r,parameters:t,operationId:o},i))}}}};var $t=n(39),Gt=n.n($t),Zt=n(40),Xt=n.n(Zt),Qt=n(41),en=n.n(Qt),tn=n(19),nn=n.n(tn),rn=n(42),on=n.n(rn),an={body:function(e){var t=e.req,n=e.value;t.body=n},header:function(e){var t=e.req,n=e.parameter,r=e.value;t.headers=t.headers||{},void 0!==r&&(t.headers[n.name]=r)},query:function(e){var t=e.req,n=e.value,r=e.parameter;t.query=t.query||{},!1===n&&"boolean"===r.type&&(n="false");0===n&&["number","integer"].indexOf(r.type)>-1&&(n="0");if(n)t.query[r.name]={collectionFormat:r.collectionFormat,value:n};else if(r.allowEmptyValue&&void 0!==n){var o=r.name;t.query[o]=t.query[o]||{},t.query[o].allowEmptyValue=!0}},path:function(e){var t=e.req,n=e.value,r=e.parameter;t.url=t.url.split("{".concat(r.name,"}")).join(encodeURIComponent(n))},formData:function(e){var t=e.req,n=e.value,r=e.parameter;(n||r.allowEmptyValue)&&(t.form=t.form||{},t.form[r.name]={value:n,allowEmptyValue:r.allowEmptyValue,collectionFormat:r.collectionFormat})}};n(49);var sn=n(43),un=n.n(sn),cn=n(44),ln=function(e){return":/?#[]@!$&'()*+,;=".indexOf(e)>-1},pn=function(e){return/^[a-z0-9\-._~]+$/i.test(e)};function fn(e){var t=(arguments.length>1&&void 0!==arguments[1]?arguments[1]:{}).escape,n=arguments.length>2?arguments[2]:void 0;return"number"==typeof e&&(e=e.toString()),"string"==typeof e&&e.length&&t?n?JSON.parse(e):Object(cn.stringToCharArray)(e).map(function(e){return pn(e)?e:ln(e)&&"unsafe"===t?e:(un()(e)||[]).map(function(e){return"0".concat(e.toString(16).toUpperCase()).slice(-2)}).map(function(e){return"%".concat(e)}).join("")}).join(""):e}function hn(e){var t=e.value;return M()(t)?function(e){var t=e.key,n=e.value,r=e.style,o=e.explode,i=e.escape,a=function(e){return fn(e,{escape:i})};if("simple"===r)return n.map(function(e){return a(e)}).join(",");if("label"===r)return".".concat(n.map(function(e){return a(e)}).join("."));if("matrix"===r)return n.map(function(e){return a(e)}).reduce(function(e,n){return!e||o?"".concat(e||"",";").concat(t,"=").concat(n):"".concat(e,",").concat(n)},"");if("form"===r){var s=o?"&".concat(t,"="):",";return n.map(function(e){return a(e)}).join(s)}if("spaceDelimited"===r){var u=o?"".concat(t,"="):"";return n.map(function(e){return a(e)}).join(" ".concat(u))}if("pipeDelimited"===r){var c=o?"".concat(t,"="):"";return n.map(function(e){return a(e)}).join("|".concat(c))}}(e):"object"===P()(t)?function(e){var t=e.key,n=e.value,r=e.style,o=e.explode,i=e.escape,a=function(e){return fn(e,{escape:i})},s=m()(n);if("simple"===r)return s.reduce(function(e,t){var r=a(n[t]),i=o?"=":",",s=e?"".concat(e,","):"";return"".concat(s).concat(t).concat(i).concat(r)},"");if("label"===r)return s.reduce(function(e,t){var r=a(n[t]),i=o?"=":".",s=e?"".concat(e,"."):".";return"".concat(s).concat(t).concat(i).concat(r)},"");if("matrix"===r&&o)return s.reduce(function(e,t){var r=a(n[t]),o=e?"".concat(e,";"):";";return"".concat(o).concat(t,"=").concat(r)},"");if("matrix"===r)return s.reduce(function(e,r){var o=a(n[r]),i=e?"".concat(e,","):";".concat(t,"=");return"".concat(i).concat(r,",").concat(o)},"");if("form"===r)return s.reduce(function(e,t){var r=a(n[t]),i=e?"".concat(e).concat(o?"&":","):"",s=o?"=":",";return"".concat(i).concat(t).concat(s).concat(r)},"")}(e):function(e){var t=e.key,n=e.value,r=e.style,o=e.escape,i=function(e){return fn(e,{escape:o})};if("simple"===r)return i(n);if("label"===r)return".".concat(i(n));if("matrix"===r)return";".concat(t,"=").concat(i(n));if("form"===r)return i(n);if("deepObject"===r)return i(n)}(e)}function dn(e,t){return t.includes("application/json")?"string"==typeof e?e:T()(e):e.toString()}function mn(e){var t=e.req,n=e.value,r=e.parameter,o=r.name,i=r.style,a=r.explode,s=r.content;if(s){var u=m()(s)[0];t.url=t.url.split("{".concat(o,"}")).join(fn(dn(n,u),{escape:!0}))}else{var c=hn({key:r.name,value:n,style:i||"simple",explode:a||!1,escape:!0});t.url=t.url.split("{".concat(o,"}")).join(c)}}function vn(e){var t=e.req,n=e.value,r=e.parameter;if(t.query=t.query||{},r.content){var o=m()(r.content)[0];t.query[r.name]=dn(n,o)}else if(!1===n&&(n="false"),0===n&&(n="0"),n){var i=P()(n);if("deepObject"===r.style)m()(n).forEach(function(e){var o=n[e];t.query["".concat(r.name,"[").concat(e,"]")]={value:hn({key:e,value:o,style:"deepObject",escape:r.allowReserved?"unsafe":"reserved"}),skipEncoding:!0}});else if("object"!==i||M()(n)||"form"!==r.style&&r.style||!r.explode&&void 0!==r.explode){var a=encodeURIComponent(r.name);t.query[a]={value:hn({key:a,value:n,style:r.style||"form",explode:void 0===r.explode||r.explode,escape:r.allowReserved?"unsafe":"reserved"}),skipEncoding:!0}}else{m()(n).forEach(function(e){var o=n[e];t.query[e]={value:hn({key:e,value:o,style:r.style||"form",escape:r.allowReserved?"unsafe":"reserved"}),skipEncoding:!0}})}}else if(r.allowEmptyValue&&void 0!==n){var s=r.name;t.query[s]=t.query[s]||{},t.query[s].allowEmptyValue=!0}}var gn=["accept","authorization","content-type"];function yn(e){var t=e.req,n=e.parameter,r=e.value;if(t.headers=t.headers||{},!(gn.indexOf(n.name.toLowerCase())>-1))if(n.content){var o=m()(n.content)[0];t.headers[n.name]=dn(r,o)}else void 0!==r&&(t.headers[n.name]=hn({key:n.name,value:r,style:n.style||"simple",explode:void 0!==n.explode&&n.explode,escape:!1}))}function bn(e){var t=e.req,n=e.parameter,r=e.value;t.headers=t.headers||{};var o=P()(r);if(n.content){var i=m()(n.content)[0];t.headers.Cookie="".concat(n.name,"=").concat(dn(r,i))}else if("undefined"!==o){var a="object"===o&&!M()(r)&&n.explode?"":"".concat(n.name,"=");t.headers.Cookie=a+hn({key:n.name,value:r,escape:!1,style:n.style||"form",explode:void 0!==n.explode&&n.explode})}}var _n=n(30),wn=function(e,t){var n=e.operation,r=e.requestBody,o=e.securities,i=e.spec,a=e.attachContentTypeForEmptyPayload,s=e.requestContentType;t=function(e){var t=e.request,n=e.securities,r=void 0===n?{}:n,o=e.operation,i=void 0===o?{}:o,a=e.spec,s=b()({},t),u=r.authorized,c=void 0===u?{}:u,l=i.security||a.security||[],p=c&&!!m()(c).length,f=Ut()(a,["components","securitySchemes"])||{};if(s.headers=s.headers||{},s.query=s.query||{},!m()(r).length||!p||!l||M()(i.security)&&!i.security.length)return t;return l.forEach(function(e,t){for(var n in e){var r=c[n],o=f[n];if(r){var i=r.value||r,a=o.type;if(r)if("apiKey"===a)"query"===o.in&&(s.query[o.name]=i),"header"===o.in&&(s.headers[o.name]=i),"cookie"===o.in&&(s.cookies[o.name]=i);else if("http"===a){if("basic"===o.scheme){var u=i.username,l=i.password,p=nn()("".concat(u,":").concat(l));s.headers.Authorization="Basic ".concat(p)}"bearer"===o.scheme&&(s.headers.Authorization="Bearer ".concat(i))}else if("oauth2"===a){var h=r.token||{},d=h[o["x-tokenName"]||"access_token"],m=h.token_type;m&&"bearer"!==m.toLowerCase()||(m="Bearer"),s.headers.Authorization="".concat(m," ").concat(d)}}}}),s}({request:t,securities:o,operation:n,spec:i});var u=n.requestBody||{},c=m()(u.content||{}),l=s&&c.indexOf(s)>-1;if(r||a){if(s&&l)t.headers["Content-Type"]=s;else if(!s){var p=c[0];p&&(t.headers["Content-Type"]=p,s=p)}}else s&&l&&(t.headers["Content-Type"]=s);return r&&(s?c.indexOf(s)>-1&&("application/x-www-form-urlencoded"===s||0===s.indexOf("multipart/")?"object"===P()(r)?(t.form={},m()(r).forEach(function(e){var n,o,i=r[e];"undefined"!=typeof File&&(o=i instanceof File),"undefined"!=typeof Blob&&(o=o||i instanceof Blob),void 0!==_n.Buffer&&(o=o||_n.Buffer.isBuffer(i)),n="object"!==P()(i)||o?i:M()(i)?i.toString():T()(i),t.form[e]={value:n}})):t.form=r:t.body=r):t.body=r),t};var xn=function(e,t){var n=e.spec,r=e.operation,o=e.securities,i=e.requestContentType,a=e.attachContentTypeForEmptyPayload;if((t=function(e){var t=e.request,n=e.securities,r=void 0===n?{}:n,o=e.operation,i=void 0===o?{}:o,a=e.spec,s=b()({},t),u=r.authorized,c=void 0===u?{}:u,l=r.specSecurity,p=void 0===l?[]:l,f=i.security||p,h=c&&!!m()(c).length,d=a.securityDefinitions;if(s.headers=s.headers||{},s.query=s.query||{},!m()(r).length||!h||!f||M()(i.security)&&!i.security.length)return t;return f.forEach(function(e,t){for(var n in e){var r=c[n];if(r){var o=r.token,i=r.value||r,a=d[n],u=a.type,l=a["x-tokenName"]||"access_token",p=o&&o[l],f=o&&o.token_type;if(r)if("apiKey"===u){var h="query"===a.in?"query":"headers";s[h]=s[h]||{},s[h][a.name]=i}else"basic"===u?i.header?s.headers.authorization=i.header:(i.base64=nn()("".concat(i.username,":").concat(i.password)),s.headers.authorization="Basic ".concat(i.base64)):"oauth2"===u&&p&&(f=f&&"bearer"!==f.toLowerCase()?f:"Bearer",s.headers.authorization="".concat(f," ").concat(p))}}}),s}({request:t,securities:o,operation:r,spec:n})).body||t.form||a)i?t.headers["Content-Type"]=i:M()(r.consumes)?t.headers["Content-Type"]=r.consumes[0]:M()(n.consumes)?t.headers["Content-Type"]=n.consumes[0]:r.parameters&&r.parameters.filter(function(e){return"file"===e.type}).length?t.headers["Content-Type"]="multipart/form-data":r.parameters&&r.parameters.filter(function(e){return"formData"===e.in}).length&&(t.headers["Content-Type"]="application/x-www-form-urlencoded");else if(i){var s=r.parameters&&r.parameters.filter(function(e){return"body"===e.in}).length>0,u=r.parameters&&r.parameters.filter(function(e){return"formData"===e.in}).length>0;(s||u)&&(t.headers["Content-Type"]=i)}return t};function En(e,t){var n=m()(e);if(h.a){var r=h()(e);t&&(r=r.filter(function(t){return p()(e,t).enumerable})),n.push.apply(n,r)}return n}function Sn(e){for(var t=1;t-1&&(c=o,l=u[p.indexOf(o)])}return!c&&u&&u.length&&(c=u[0].url,l=u[0]),c.indexOf("{")>-1&&function(e){for(var t,n=[],r=/{([^}]+)}/g;t=r.exec(e);)n.push(t[1]);return n}(c).forEach(function(e){if(l.variables&&l.variables[e]){var t=l.variables[e],n=s[e]||t.default,r=new RegExp("{".concat(e,"}"),"g");c=c.replace(r,n)}}),function(){var e,t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"",n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"",r=E.a.parse(t),o=E.a.parse(n),i=Pn(r.protocol)||Pn(o.protocol)||"",a=r.host||o.host,s=r.pathname||"";return"/"===(e=i&&a?"".concat(i,"://").concat(a+s):s)[e.length-1]?e.slice(0,-1):e}(c,i)}(b):function(e){var t,n=e.spec,r=e.scheme,o=e.contextUrl,i=void 0===o?"":o,a=E.a.parse(i),s=M()(n.schemes)?n.schemes[0]:null,u=r||s||Pn(a.protocol)||"http",c=n.host||a.host||"",l=n.basePath||"";return"/"===(t=u&&c?"".concat(u,"://").concat(c+l):l)[t.length-1]?t.slice(0,-1):t}(b),!n)return delete g.cookies,g;g.url+=S,g.method="".concat(x).toUpperCase(),h=h||{};var C=t.paths[S]||{};o&&(g.headers.accept=o);var k=An([].concat(Cn(w.parameters)).concat(Cn(C.parameters)));k.forEach(function(e){var n,r=d[e.in];if("body"===e.in&&e.schema&&e.schema.properties&&(n=h),void 0===(n=e&&e.name&&h[e.name])?n=e&&e.name&&h["".concat(e.in,".").concat(e.name)]:On(e.name,k).length>1&&console.warn("Parameter '".concat(e.name,"' is ambiguous because the defined spec has more than one parameter with the name: '").concat(e.name,"' and the passed-in parameter values did not define an 'in' value.")),null!==n){if(void 0!==e.default&&void 0===n&&(n=e.default),void 0===n&&e.required&&!e.allowEmptyValue)throw new Error("Required parameter ".concat(e.name," is not provided"));if(v&&e.schema&&"object"===e.schema.type&&"string"==typeof n)try{n=JSON.parse(n)}catch(e){throw new Error("Could not parse object parameter value string as JSON")}r&&r({req:g,parameter:e,value:n,operation:w,spec:t})}});var O=Sn({},e,{operation:w});if((g=v?wn(O,g):xn(O,g)).cookies&&m()(g.cookies).length){var A=m()(g.cookies).reduce(function(e,t){var n=g.cookies[t];return e+(e?"&":"")+on.a.serialize(t,n)},"");g.headers.Cookie=A}return g.cookies&&delete g.cookies,Z(g),g}var Pn=function(e){return e?e.replace(/\W/g,""):null};function In(e,t){var n=m()(e);if(h.a){var r=h()(e);t&&(r=r.filter(function(t){return p()(e,t).enumerable})),n.push.apply(n,r)}return n}function Mn(e){var t=this,n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};if("string"==typeof e?n.url=e:n=e,!(this instanceof Mn))return new Mn(n);b()(this,n);var r=this.resolve().then(function(){return t.disableInterfaces||b()(t,Mn.makeApisTagOperation(t)),t});return r.client=this,r}Mn.http=V,Mn.makeHttp=function(e,t,n){return n=n||function(e){return e},t=t||function(e){return e},function(r){return"string"==typeof r&&(r={url:r}),z.mergeInQueryOrForm(r),r=t(r),n(e(r))}}.bind(null,Mn.http),Mn.resolve=Dt,Mn.resolveSubtree=function(e,t){return Bt.apply(this,arguments)},Mn.execute=function(e){var t=e.http,n=e.fetch,r=e.spec,o=e.operationId,i=e.pathName,a=e.method,s=e.parameters,u=e.securities,c=Gt()(e,["http","fetch","spec","operationId","pathName","method","parameters","securities"]),l=t||n||V;i&&a&&!o&&(o=Pt(i,a));var p=Tn.buildRequest(Sn({spec:r,operationId:o,parameters:s,securities:u,http:l},c));return p.body&&(Xt()(p.body)||en()(p.body))&&(p.body=T()(p.body)),l(p)},Mn.serializeRes=J,Mn.serializeHeaders=K,Mn.clearCache=function(){St.refs.clearCache()},Mn.makeApisTagOperation=function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},t=Yt.makeExecute(e);return{apis:Yt.mapTagOperations({v2OperationIdCompatibilityMode:e.v2OperationIdCompatibilityMode,spec:e.spec,cb:t})}},Mn.buildRequest=jn,Mn.helpers={opId:jt},Mn.prototype={http:V,execute:function(e){return this.applyDefaults(),Mn.execute(function(e){for(var t=1;t 
+ * @license  MIT
+ */
+var r=n(569),o=n(570),i=n(355);function a(){return u.TYPED_ARRAY_SUPPORT?2147483647:1073741823}function s(e,t){if(a()=a())throw new RangeError("Attempt to allocate Buffer larger than maximum size: 0x"+a().toString(16)+" bytes");return 0|e}function d(e,t){if(u.isBuffer(e))return e.length;if("undefined"!=typeof ArrayBuffer&&"function"==typeof ArrayBuffer.isView&&(ArrayBuffer.isView(e)||e instanceof ArrayBuffer))return e.byteLength;"string"!=typeof e&&(e=""+e);var n=e.length;if(0===n)return 0;for(var r=!1;;)switch(t){case"ascii":case"latin1":case"binary":return n;case"utf8":case"utf-8":case void 0:return B(e).length;case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return 2*n;case"hex":return n>>>1;case"base64":return z(e).length;default:if(r)return B(e).length;t=(""+t).toLowerCase(),r=!0}}function m(e,t,n){var r=!1;if((void 0===t||t<0)&&(t=0),t>this.length)return"";if((void 0===n||n>this.length)&&(n=this.length),n<=0)return"";if((n>>>=0)<=(t>>>=0))return"";for(e||(e="utf8");;)switch(e){case"hex":return j(this,t,n);case"utf8":case"utf-8":return k(this,t,n);case"ascii":return A(this,t,n);case"latin1":case"binary":return T(this,t,n);case"base64":return C(this,t,n);case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return P(this,t,n);default:if(r)throw new TypeError("Unknown encoding: "+e);e=(e+"").toLowerCase(),r=!0}}function v(e,t,n){var r=e[t];e[t]=e[n],e[n]=r}function g(e,t,n,r,o){if(0===e.length)return-1;if("string"==typeof n?(r=n,n=0):n>2147483647?n=2147483647:n<-2147483648&&(n=-2147483648),n=+n,isNaN(n)&&(n=o?0:e.length-1),n<0&&(n=e.length+n),n>=e.length){if(o)return-1;n=e.length-1}else if(n<0){if(!o)return-1;n=0}if("string"==typeof t&&(t=u.from(t,r)),u.isBuffer(t))return 0===t.length?-1:y(e,t,n,r,o);if("number"==typeof t)return t&=255,u.TYPED_ARRAY_SUPPORT&&"function"==typeof Uint8Array.prototype.indexOf?o?Uint8Array.prototype.indexOf.call(e,t,n):Uint8Array.prototype.lastIndexOf.call(e,t,n):y(e,[t],n,r,o);throw new TypeError("val must be string, number or Buffer")}function y(e,t,n,r,o){var i,a=1,s=e.length,u=t.length;if(void 0!==r&&("ucs2"===(r=String(r).toLowerCase())||"ucs-2"===r||"utf16le"===r||"utf-16le"===r)){if(e.length<2||t.length<2)return-1;a=2,s/=2,u/=2,n/=2}function c(e,t){return 1===a?e[t]:e.readUInt16BE(t*a)}if(o){var l=-1;for(i=n;is&&(n=s-u),i=n;i>=0;i--){for(var p=!0,f=0;fo&&(r=o):r=o;var i=t.length;if(i%2!=0)throw new TypeError("Invalid hex string");r>i/2&&(r=i/2);for(var a=0;a>8,o=n%256,i.push(o),i.push(r);return i}(t,e.length-n),e,n,r)}function C(e,t,n){return 0===t&&n===e.length?r.fromByteArray(e):r.fromByteArray(e.slice(t,n))}function k(e,t,n){n=Math.min(e.length,n);for(var r=[],o=t;o239?4:c>223?3:c>191?2:1;if(o+p<=n)switch(p){case 1:c<128&&(l=c);break;case 2:128==(192&(i=e[o+1]))&&(u=(31&c)<<6|63&i)>127&&(l=u);break;case 3:i=e[o+1],a=e[o+2],128==(192&i)&&128==(192&a)&&(u=(15&c)<<12|(63&i)<<6|63&a)>2047&&(u<55296||u>57343)&&(l=u);break;case 4:i=e[o+1],a=e[o+2],s=e[o+3],128==(192&i)&&128==(192&a)&&128==(192&s)&&(u=(15&c)<<18|(63&i)<<12|(63&a)<<6|63&s)>65535&&u<1114112&&(l=u)}null===l?(l=65533,p=1):l>65535&&(l-=65536,r.push(l>>>10&1023|55296),l=56320|1023&l),r.push(l),o+=p}return function(e){var t=e.length;if(t<=O)return String.fromCharCode.apply(String,e);var n="",r=0;for(;r0&&(e=this.toString("hex",0,n).match(/.{2}/g).join(" "),this.length>n&&(e+=" ... ")),""},u.prototype.compare=function(e,t,n,r,o){if(!u.isBuffer(e))throw new TypeError("Argument must be a Buffer");if(void 0===t&&(t=0),void 0===n&&(n=e?e.length:0),void 0===r&&(r=0),void 0===o&&(o=this.length),t<0||n>e.length||r<0||o>this.length)throw new RangeError("out of range index");if(r>=o&&t>=n)return 0;if(r>=o)return-1;if(t>=n)return 1;if(this===e)return 0;for(var i=(o>>>=0)-(r>>>=0),a=(n>>>=0)-(t>>>=0),s=Math.min(i,a),c=this.slice(r,o),l=e.slice(t,n),p=0;po)&&(n=o),e.length>0&&(n<0||t<0)||t>this.length)throw new RangeError("Attempt to write outside buffer bounds");r||(r="utf8");for(var i=!1;;)switch(r){case"hex":return b(this,e,t,n);case"utf8":case"utf-8":return _(this,e,t,n);case"ascii":return w(this,e,t,n);case"latin1":case"binary":return x(this,e,t,n);case"base64":return E(this,e,t,n);case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return S(this,e,t,n);default:if(i)throw new TypeError("Unknown encoding: "+r);r=(""+r).toLowerCase(),i=!0}},u.prototype.toJSON=function(){return{type:"Buffer",data:Array.prototype.slice.call(this._arr||this,0)}};var O=4096;function A(e,t,n){var r="";n=Math.min(e.length,n);for(var o=t;or)&&(n=r);for(var o="",i=t;in)throw new RangeError("Trying to access beyond buffer length")}function M(e,t,n,r,o,i){if(!u.isBuffer(e))throw new TypeError('"buffer" argument must be a Buffer instance');if(t>o||te.length)throw new RangeError("Index out of range")}function N(e,t,n,r){t<0&&(t=65535+t+1);for(var o=0,i=Math.min(e.length-n,2);o>>8*(r?o:1-o)}function R(e,t,n,r){t<0&&(t=4294967295+t+1);for(var o=0,i=Math.min(e.length-n,4);o>>8*(r?o:3-o)&255}function D(e,t,n,r,o,i){if(n+r>e.length)throw new RangeError("Index out of range");if(n<0)throw new RangeError("Index out of range")}function L(e,t,n,r,i){return i||D(e,0,n,4),o.write(e,t,n,r,23,4),n+4}function U(e,t,n,r,i){return i||D(e,0,n,8),o.write(e,t,n,r,52,8),n+8}u.prototype.slice=function(e,t){var n,r=this.length;if((e=~~e)<0?(e+=r)<0&&(e=0):e>r&&(e=r),(t=void 0===t?r:~~t)<0?(t+=r)<0&&(t=0):t>r&&(t=r),t0&&(o*=256);)r+=this[e+--t]*o;return r},u.prototype.readUInt8=function(e,t){return t||I(e,1,this.length),this[e]},u.prototype.readUInt16LE=function(e,t){return t||I(e,2,this.length),this[e]|this[e+1]<<8},u.prototype.readUInt16BE=function(e,t){return t||I(e,2,this.length),this[e]<<8|this[e+1]},u.prototype.readUInt32LE=function(e,t){return t||I(e,4,this.length),(this[e]|this[e+1]<<8|this[e+2]<<16)+16777216*this[e+3]},u.prototype.readUInt32BE=function(e,t){return t||I(e,4,this.length),16777216*this[e]+(this[e+1]<<16|this[e+2]<<8|this[e+3])},u.prototype.readIntLE=function(e,t,n){e|=0,t|=0,n||I(e,t,this.length);for(var r=this[e],o=1,i=0;++i=(o*=128)&&(r-=Math.pow(2,8*t)),r},u.prototype.readIntBE=function(e,t,n){e|=0,t|=0,n||I(e,t,this.length);for(var r=t,o=1,i=this[e+--r];r>0&&(o*=256);)i+=this[e+--r]*o;return i>=(o*=128)&&(i-=Math.pow(2,8*t)),i},u.prototype.readInt8=function(e,t){return t||I(e,1,this.length),128&this[e]?-1*(255-this[e]+1):this[e]},u.prototype.readInt16LE=function(e,t){t||I(e,2,this.length);var n=this[e]|this[e+1]<<8;return 32768&n?4294901760|n:n},u.prototype.readInt16BE=function(e,t){t||I(e,2,this.length);var n=this[e+1]|this[e]<<8;return 32768&n?4294901760|n:n},u.prototype.readInt32LE=function(e,t){return t||I(e,4,this.length),this[e]|this[e+1]<<8|this[e+2]<<16|this[e+3]<<24},u.prototype.readInt32BE=function(e,t){return t||I(e,4,this.length),this[e]<<24|this[e+1]<<16|this[e+2]<<8|this[e+3]},u.prototype.readFloatLE=function(e,t){return t||I(e,4,this.length),o.read(this,e,!0,23,4)},u.prototype.readFloatBE=function(e,t){return t||I(e,4,this.length),o.read(this,e,!1,23,4)},u.prototype.readDoubleLE=function(e,t){return t||I(e,8,this.length),o.read(this,e,!0,52,8)},u.prototype.readDoubleBE=function(e,t){return t||I(e,8,this.length),o.read(this,e,!1,52,8)},u.prototype.writeUIntLE=function(e,t,n,r){(e=+e,t|=0,n|=0,r)||M(this,e,t,n,Math.pow(2,8*n)-1,0);var o=1,i=0;for(this[t]=255&e;++i=0&&(i*=256);)this[t+o]=e/i&255;return t+n},u.prototype.writeUInt8=function(e,t,n){return e=+e,t|=0,n||M(this,e,t,1,255,0),u.TYPED_ARRAY_SUPPORT||(e=Math.floor(e)),this[t]=255&e,t+1},u.prototype.writeUInt16LE=function(e,t,n){return e=+e,t|=0,n||M(this,e,t,2,65535,0),u.TYPED_ARRAY_SUPPORT?(this[t]=255&e,this[t+1]=e>>>8):N(this,e,t,!0),t+2},u.prototype.writeUInt16BE=function(e,t,n){return e=+e,t|=0,n||M(this,e,t,2,65535,0),u.TYPED_ARRAY_SUPPORT?(this[t]=e>>>8,this[t+1]=255&e):N(this,e,t,!1),t+2},u.prototype.writeUInt32LE=function(e,t,n){return e=+e,t|=0,n||M(this,e,t,4,4294967295,0),u.TYPED_ARRAY_SUPPORT?(this[t+3]=e>>>24,this[t+2]=e>>>16,this[t+1]=e>>>8,this[t]=255&e):R(this,e,t,!0),t+4},u.prototype.writeUInt32BE=function(e,t,n){return e=+e,t|=0,n||M(this,e,t,4,4294967295,0),u.TYPED_ARRAY_SUPPORT?(this[t]=e>>>24,this[t+1]=e>>>16,this[t+2]=e>>>8,this[t+3]=255&e):R(this,e,t,!1),t+4},u.prototype.writeIntLE=function(e,t,n,r){if(e=+e,t|=0,!r){var o=Math.pow(2,8*n-1);M(this,e,t,n,o-1,-o)}var i=0,a=1,s=0;for(this[t]=255&e;++i>0)-s&255;return t+n},u.prototype.writeIntBE=function(e,t,n,r){if(e=+e,t|=0,!r){var o=Math.pow(2,8*n-1);M(this,e,t,n,o-1,-o)}var i=n-1,a=1,s=0;for(this[t+i]=255&e;--i>=0&&(a*=256);)e<0&&0===s&&0!==this[t+i+1]&&(s=1),this[t+i]=(e/a>>0)-s&255;return t+n},u.prototype.writeInt8=function(e,t,n){return e=+e,t|=0,n||M(this,e,t,1,127,-128),u.TYPED_ARRAY_SUPPORT||(e=Math.floor(e)),e<0&&(e=255+e+1),this[t]=255&e,t+1},u.prototype.writeInt16LE=function(e,t,n){return e=+e,t|=0,n||M(this,e,t,2,32767,-32768),u.TYPED_ARRAY_SUPPORT?(this[t]=255&e,this[t+1]=e>>>8):N(this,e,t,!0),t+2},u.prototype.writeInt16BE=function(e,t,n){return e=+e,t|=0,n||M(this,e,t,2,32767,-32768),u.TYPED_ARRAY_SUPPORT?(this[t]=e>>>8,this[t+1]=255&e):N(this,e,t,!1),t+2},u.prototype.writeInt32LE=function(e,t,n){return e=+e,t|=0,n||M(this,e,t,4,2147483647,-2147483648),u.TYPED_ARRAY_SUPPORT?(this[t]=255&e,this[t+1]=e>>>8,this[t+2]=e>>>16,this[t+3]=e>>>24):R(this,e,t,!0),t+4},u.prototype.writeInt32BE=function(e,t,n){return e=+e,t|=0,n||M(this,e,t,4,2147483647,-2147483648),e<0&&(e=4294967295+e+1),u.TYPED_ARRAY_SUPPORT?(this[t]=e>>>24,this[t+1]=e>>>16,this[t+2]=e>>>8,this[t+3]=255&e):R(this,e,t,!1),t+4},u.prototype.writeFloatLE=function(e,t,n){return L(this,e,t,!0,n)},u.prototype.writeFloatBE=function(e,t,n){return L(this,e,t,!1,n)},u.prototype.writeDoubleLE=function(e,t,n){return U(this,e,t,!0,n)},u.prototype.writeDoubleBE=function(e,t,n){return U(this,e,t,!1,n)},u.prototype.copy=function(e,t,n,r){if(n||(n=0),r||0===r||(r=this.length),t>=e.length&&(t=e.length),t||(t=0),r>0&&r=this.length)throw new RangeError("sourceStart out of bounds");if(r<0)throw new RangeError("sourceEnd out of bounds");r>this.length&&(r=this.length),e.length-t=0;--o)e[o+t]=this[o+n];else if(i<1e3||!u.TYPED_ARRAY_SUPPORT)for(o=0;o>>=0,n=void 0===n?this.length:n>>>0,e||(e=0),"number"==typeof e)for(i=t;i55295&&n<57344){if(!o){if(n>56319){(t-=3)>-1&&i.push(239,191,189);continue}if(a+1===r){(t-=3)>-1&&i.push(239,191,189);continue}o=n;continue}if(n<56320){(t-=3)>-1&&i.push(239,191,189),o=n;continue}n=65536+(o-55296<<10|n-56320)}else o&&(t-=3)>-1&&i.push(239,191,189);if(o=null,n<128){if((t-=1)<0)break;i.push(n)}else if(n<2048){if((t-=2)<0)break;i.push(n>>6|192,63&n|128)}else if(n<65536){if((t-=3)<0)break;i.push(n>>12|224,n>>6&63|128,63&n|128)}else{if(!(n<1114112))throw new Error("Invalid code point");if((t-=4)<0)break;i.push(n>>18|240,n>>12&63|128,n>>6&63|128,63&n|128)}}return i}function z(e){return r.toByteArray(function(e){if((e=function(e){return e.trim?e.trim():e.replace(/^\s+|\s+$/g,"")}(e).replace(q,"")).length<2)return"";for(;e.length%4!=0;)e+="=";return e}(e))}function V(e,t,n,r){for(var o=0;o=t.length||o>=e.length);++o)t[o+n]=e[o];return o}}).call(this,n(36))},function(e,t,n){"use strict";e.exports={current:null}},function(e,t){e.exports=function(e){return null!=e&&"object"==typeof e}},function(e,t){var n,r,o=e.exports={};function i(){throw new Error("setTimeout has not been defined")}function a(){throw new Error("clearTimeout has not been defined")}function s(e){if(n===setTimeout)return setTimeout(e,0);if((n===i||!n)&&setTimeout)return n=setTimeout,setTimeout(e,0);try{return n(e,0)}catch(t){try{return n.call(null,e,0)}catch(t){return n.call(this,e,0)}}}!function(){try{n="function"==typeof setTimeout?setTimeout:i}catch(e){n=i}try{r="function"==typeof clearTimeout?clearTimeout:a}catch(e){r=a}}();var u,c=[],l=!1,p=-1;function f(){l&&u&&(l=!1,u.length?c=u.concat(c):p=-1,c.length&&h())}function h(){if(!l){var e=s(f);l=!0;for(var t=c.length;t;){for(u=c,c=[];++p1)for(var n=1;n0&&"/"!==t[0]});function oe(e,t,n){return t=t||[],te.apply(void 0,[e].concat(u()(t))).get("parameters",Object(p.List)()).reduce(function(e,t){var r=n&&"body"===t.get("in")?t.get("value_xml"):t.get("value");return e.set(Object(l.B)(t,{allowHashes:!1}),r)},Object(p.fromJS)({}))}function ie(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"";if(p.List.isList(e))return e.some(function(e){return p.Map.isMap(e)&&e.get("in")===t})}function ae(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"";if(p.List.isList(e))return e.some(function(e){return p.Map.isMap(e)&&e.get("type")===t})}function se(e,t){t=t||[];var n=x(e).getIn(["paths"].concat(u()(t)),Object(p.fromJS)({})),r=e.getIn(["meta","paths"].concat(u()(t)),Object(p.fromJS)({})),o=ue(e,t),i=n.get("parameters")||new p.List,a=r.get("consumes_value")?r.get("consumes_value"):ae(i,"file")?"multipart/form-data":ae(i,"formData")?"application/x-www-form-urlencoded":void 0;return Object(p.fromJS)({requestContentType:a,responseContentType:o})}function ue(e,t){t=t||[];var n=x(e).getIn(["paths"].concat(u()(t)),null);if(null!==n){var r=e.getIn(["meta","paths"].concat(u()(t),["produces_value"]),null),o=n.getIn(["produces",0],null);return r||o||"application/json"}}function ce(e,t){t=t||[];var n=x(e),r=n.getIn(["paths"].concat(u()(t)),null);if(null!==r){var o=t,i=a()(o,1)[0],s=r.get("produces",null),c=n.getIn(["paths",i,"produces"],null),l=n.getIn(["produces"],null);return s||c||l}}function le(e,t){t=t||[];var n=x(e),r=n.getIn(["paths"].concat(u()(t)),null);if(null!==r){var o=t,i=a()(o,1)[0],s=r.get("consumes",null),c=n.getIn(["paths",i,"consumes"],null),l=n.getIn(["consumes"],null);return s||c||l}}var pe=function(e,t,n){var r=e.get("url").match(/^([a-z][a-z0-9+\-.]*):/),i=o()(r)?r[1]:null;return e.getIn(["scheme",t,n])||e.getIn(["scheme","_defaultScheme"])||i||""},fe=function(e,t,n){return["http","https"].indexOf(pe(e,t,n))>-1},he=function(e,t){t=t||[];var n=e.getIn(["meta","paths"].concat(u()(t),["parameters"]),Object(p.fromJS)([])),r=!0;return n.forEach(function(e){var t=e.get("errors");t&&t.count()&&(r=!1)}),r};function de(e){return p.Map.isMap(e)?e:new p.Map}},function(e,t,n){"use strict";n.r(t),n.d(t,"SHOW_AUTH_POPUP",function(){return d}),n.d(t,"AUTHORIZE",function(){return m}),n.d(t,"LOGOUT",function(){return v}),n.d(t,"PRE_AUTHORIZE_OAUTH2",function(){return g}),n.d(t,"AUTHORIZE_OAUTH2",function(){return y}),n.d(t,"VALIDATE",function(){return b}),n.d(t,"CONFIGURE_AUTH",function(){return _}),n.d(t,"showDefinitions",function(){return w}),n.d(t,"authorize",function(){return x}),n.d(t,"logout",function(){return E}),n.d(t,"preAuthorizeImplicit",function(){return S}),n.d(t,"authorizeOauth2",function(){return C}),n.d(t,"authorizePassword",function(){return k}),n.d(t,"authorizeApplication",function(){return O}),n.d(t,"authorizeAccessCodeWithFormParams",function(){return A}),n.d(t,"authorizeAccessCodeWithBasicAuthentication",function(){return T}),n.d(t,"authorizeRequest",function(){return j}),n.d(t,"configureAuth",function(){return P});var r=n(26),o=n.n(r),i=n(16),a=n.n(i),s=n(28),u=n.n(s),c=n(95),l=n.n(c),p=n(18),f=n.n(p),h=n(3),d="show_popup",m="authorize",v="logout",g="pre_authorize_oauth2",y="authorize_oauth2",b="validate",_="configure_auth";function w(e){return{type:d,payload:e}}function x(e){return{type:m,payload:e}}function E(e){return{type:v,payload:e}}var S=function(e){return function(t){var n=t.authActions,r=t.errActions,o=e.auth,i=e.token,a=e.isValid,s=o.schema,c=o.name,l=s.get("flow");delete f.a.swaggerUIRedirectOauth2,"accessCode"===l||a||r.newAuthErr({authId:c,source:"auth",level:"warning",message:"Authorization may be unsafe, passed state was changed in server Passed state wasn't returned from auth server"}),i.error?r.newAuthErr({authId:c,source:"auth",level:"error",message:u()(i)}):n.authorizeOauth2({auth:o,token:i})}};function C(e){return{type:y,payload:e}}var k=function(e){return function(t){var n=t.authActions,r=e.schema,o=e.name,i=e.username,s=e.password,u=e.passwordType,c=e.clientId,l=e.clientSecret,p={grant_type:"password",scope:e.scopes.join(" "),username:i,password:s},f={};switch(u){case"request-body":!function(e,t,n){t&&a()(e,{client_id:t});n&&a()(e,{client_secret:n})}(p,c,l);break;case"basic":f.Authorization="Basic "+Object(h.a)(c+":"+l);break;default:console.warn("Warning: invalid passwordType ".concat(u," was passed, not including client id and secret"))}return n.authorizeRequest({body:Object(h.b)(p),url:r.get("tokenUrl"),name:o,headers:f,query:{},auth:e})}};var O=function(e){return function(t){var n=t.authActions,r=e.schema,o=e.scopes,i=e.name,a=e.clientId,s=e.clientSecret,u={Authorization:"Basic "+Object(h.a)(a+":"+s)},c={grant_type:"client_credentials",scope:o.join(" ")};return n.authorizeRequest({body:Object(h.b)(c),name:i,url:r.get("tokenUrl"),auth:e,headers:u})}},A=function(e){var t=e.auth,n=e.redirectUrl;return function(e){var r=e.authActions,o=t.schema,i=t.name,a=t.clientId,s=t.clientSecret,u=t.codeVerifier,c={grant_type:"authorization_code",code:t.code,client_id:a,client_secret:s,redirect_uri:n,code_verifier:u};return r.authorizeRequest({body:Object(h.b)(c),name:i,url:o.get("tokenUrl"),auth:t})}},T=function(e){var t=e.auth,n=e.redirectUrl;return function(e){var r=e.authActions,o=t.schema,i=t.name,a=t.clientId,s=t.clientSecret,u={Authorization:"Basic "+Object(h.a)(a+":"+s)},c={grant_type:"authorization_code",code:t.code,client_id:a,redirect_uri:n};return r.authorizeRequest({body:Object(h.b)(c),name:i,url:o.get("tokenUrl"),auth:t,headers:u})}},j=function(e){return function(t){var n,r=t.fn,i=t.getConfigs,s=t.authActions,c=t.errActions,p=t.oas3Selectors,f=t.specSelectors,h=t.authSelectors,d=e.body,m=e.query,v=void 0===m?{}:m,g=e.headers,y=void 0===g?{}:g,b=e.name,_=e.url,w=e.auth,x=(h.getConfigs()||{}).additionalQueryStringParams;n=f.isOAS3()?l()(_,p.selectedServer(),!0):l()(_,f.url(),!0),"object"===o()(x)&&(n.query=a()({},n.query,x));var E=n.toString(),S=a()({Accept:"application/json, text/plain, */*","Content-Type":"application/x-www-form-urlencoded","X-Requested-With":"XMLHttpRequest"},y);r.fetch({url:E,method:"post",headers:S,query:v,body:d,requestInterceptor:i().requestInterceptor,responseInterceptor:i().responseInterceptor}).then(function(e){var t=JSON.parse(e.data),n=t&&(t.error||""),r=t&&(t.parseError||"");e.ok?n||r?c.newAuthErr({authId:b,level:"error",source:"auth",message:u()(t)}):s.authorizeOauth2({auth:w,token:t}):c.newAuthErr({authId:b,level:"error",source:"auth",message:e.statusText})}).catch(function(e){var t=new Error(e).message;if(e.response&&e.response.data){var n=e.response.data;try{var r="string"==typeof n?JSON.parse(n):n;r.error&&(t+=", error: ".concat(r.error)),r.error_description&&(t+=", description: ".concat(r.error_description))}catch(e){}}c.newAuthErr({authId:b,level:"error",source:"auth",message:t})})}};function P(e){return{type:_,payload:e}}},function(e,t){var n=e.exports={version:"2.6.5"};"number"==typeof __e&&(__e=n)},function(e,t){e.exports=function(e){if(null==e)throw TypeError("Can't call method on  "+e);return e}},function(e,t,n){var r=n(127),o=Math.min;e.exports=function(e){return e>0?o(r(e),9007199254740991):0}},function(e,t){var n={}.hasOwnProperty;e.exports=function(e,t){return n.call(e,t)}},function(e,t,n){var r=n(211),o=n(210);e.exports=function(e){return r(o(e))}},function(e,t,n){var r=n(49),o=n(133);e.exports=n(50)?function(e,t,n){return r.f(e,t,o(1,n))}:function(e,t,n){return e[t]=n,e}},function(e,t,n){"use strict";e.exports=function(e){if("function"!=typeof e)throw new TypeError(e+" is not a function");return e}},function(e,t,n){"use strict";n.r(t),n.d(t,"UPDATE_LAYOUT",function(){return o}),n.d(t,"UPDATE_FILTER",function(){return i}),n.d(t,"UPDATE_MODE",function(){return a}),n.d(t,"SHOW",function(){return s}),n.d(t,"updateLayout",function(){return u}),n.d(t,"updateFilter",function(){return c}),n.d(t,"show",function(){return l}),n.d(t,"changeMode",function(){return p});var r=n(3),o="layout_update_layout",i="layout_update_filter",a="layout_update_mode",s="layout_show";function u(e){return{type:o,payload:e}}function c(e){return{type:i,payload:e}}function l(e){var t=!(arguments.length>1&&void 0!==arguments[1])||arguments[1];return e=Object(r.w)(e),{type:s,payload:{thing:e,shown:t}}}function p(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"";return e=Object(r.w)(e),{type:a,payload:{thing:e,mode:t}}}},function(e,t,n){"use strict";(function(t){
+/*!
+ * @description Recursive object extending
+ * @author Viacheslav Lotsmanov 
+ * @license MIT
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2013-2018 Viacheslav Lotsmanov
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+function n(e){return e instanceof t||e instanceof Date||e instanceof RegExp}function r(e){if(e instanceof t){var n=t.alloc?t.alloc(e.length):new t(e.length);return e.copy(n),n}if(e instanceof Date)return new Date(e.getTime());if(e instanceof RegExp)return new RegExp(e);throw new Error("Unexpected situation")}function o(e){var t=[];return e.forEach(function(e,i){"object"==typeof e&&null!==e?Array.isArray(e)?t[i]=o(e):n(e)?t[i]=r(e):t[i]=a({},e):t[i]=e}),t}function i(e,t){return"__proto__"===t?void 0:e[t]}var a=e.exports=function(){if(arguments.length<1||"object"!=typeof arguments[0])return!1;if(arguments.length<2)return arguments[0];var e,t,s=arguments[0],u=Array.prototype.slice.call(arguments,1);return u.forEach(function(u){"object"!=typeof u||null===u||Array.isArray(u)||Object.keys(u).forEach(function(c){return t=i(s,c),(e=i(u,c))===s?void 0:"object"!=typeof e||null===e?void(s[c]=e):Array.isArray(e)?void(s[c]=o(e)):n(e)?void(s[c]=r(e)):"object"!=typeof t||null===t||Array.isArray(t)?void(s[c]=a({},e)):void(s[c]=a(t,e))})}),s}}).call(this,n(64).Buffer)},function(e,t,n){var r=n(151),o=n(336);e.exports=n(126)?function(e,t,n){return r.f(e,t,o(1,n))}:function(e,t,n){return e[t]=n,e}},function(e,t){e.exports=function(e){try{return!!e()}catch(e){return!0}}},function(e,t,n){var r=n(106),o=n(603),i=n(604),a="[object Null]",s="[object Undefined]",u=r?r.toStringTag:void 0;e.exports=function(e){return null==e?void 0===e?s:a:u&&u in Object(e)?o(e):i(e)}},function(e,t,n){var r=n(621),o=n(624);e.exports=function(e,t){var n=o(e,t);return r(n)?n:void 0}},function(e,t,n){var r=n(380),o=n(661),i=n(107);e.exports=function(e){return i(e)?r(e):o(e)}},function(e,t,n){"use strict";var r=n(178),o=Object.keys||function(e){var t=[];for(var n in e)t.push(n);return t};e.exports=p;var i=n(137);i.inherits=n(47);var a=n(390),s=n(240);i.inherits(p,a);for(var u=o(s.prototype),c=0;c=t.length?{value:void 0,done:!0}:(e=r(t,n),this._i+=e.length,{value:e,done:!1})})},function(e,t){e.exports={}},function(e,t,n){n(561);for(var r=n(32),o=n(77),i=n(102),a=n(34)("toStringTag"),s="CSSRuleList,CSSStyleDeclaration,CSSValueList,ClientRectList,DOMRectList,DOMStringList,DOMTokenList,DataTransferItemList,FileList,HTMLAllCollection,HTMLCollection,HTMLFormElement,HTMLSelectElement,MediaList,MimeTypeArray,NamedNodeMap,NodeList,PaintRequestList,Plugin,PluginArray,SVGLengthList,SVGNumberList,SVGPathSegList,SVGPointList,SVGStringList,SVGTransformList,SourceBufferList,StyleSheetList,TextTrackCueList,TextTrackList,TouchList".split(","),u=0;u1){for(var d=Array(h),m=0;m1){for(var g=Array(v),y=0;y=this._finalSize&&(this._update(this._block),this._block.fill(0));var n=8*this._len;if(n<=4294967295)this._block.writeUInt32BE(n,this._blockSize-4);else{var r=(4294967295&n)>>>0,o=(n-r)/4294967296;this._block.writeUInt32BE(o,this._blockSize-8),this._block.writeUInt32BE(r,this._blockSize-4)}this._update(this._block);var i=this._hash();return e?i.toString(e):i},o.prototype._update=function(){throw new Error("_update must be implemented by subclass")},e.exports=o},function(e,t,n){var r=n(63),o=n(406),i=n(407),a=n(46),s=n(158),u=n(225),c={},l={};(t=e.exports=function(e,t,n,p,f){var h,d,m,v,g=f?function(){return e}:u(e),y=r(n,p,t?2:1),b=0;if("function"!=typeof g)throw TypeError(e+" is not iterable!");if(i(g)){for(h=s(e.length);h>b;b++)if((v=t?y(a(d=e[b])[0],d[1]):y(e[b]))===c||v===l)return v}else for(m=g.call(e);!(d=m.next()).done;)if((v=o(m,y,d.value,t))===c||v===l)return v}).BREAK=c,t.RETURN=l},function(e,t,n){"use strict";function r(e){return null==e}e.exports.isNothing=r,e.exports.isObject=function(e){return"object"==typeof e&&null!==e},e.exports.toArray=function(e){return Array.isArray(e)?e:r(e)?[]:[e]},e.exports.repeat=function(e,t){var n,r="";for(n=0;n1&&void 0!==arguments[1]?arguments[1]:{},r=Object(i.A)(t),a=r.type,s=r.example,u=r.properties,c=r.additionalProperties,l=r.items,p=n.includeReadOnly,f=n.includeWriteOnly;if(void 0!==s)return Object(i.e)(s,"$$ref",function(e){return"string"==typeof e&&e.indexOf("#")>-1});if(!a)if(u)a="object";else{if(!l)return;a="array"}if("object"===a){var d=Object(i.A)(u),m={};for(var v in d)d[v]&&d[v].deprecated||d[v]&&d[v].readOnly&&!p||d[v]&&d[v].writeOnly&&!f||(m[v]=e(d[v],n));if(!0===c)m.additionalProp1={};else if(c)for(var g=Object(i.A)(c),y=e(g,n),b=1;b<4;b++)m["additionalProp"+b]=y;return m}return"array"===a?o()(l.anyOf)?l.anyOf.map(function(t){return e(t,n)}):o()(l.oneOf)?l.oneOf.map(function(t){return e(t,n)}):[e(l,n)]:t.enum?t.default?t.default:Object(i.w)(t.enum)[0]:"file"!==a?h(t):void 0},m=function(e){return e.schema&&(e=e.schema),e.properties&&(e.type="object"),e},v=function e(t){var n,r,a=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},s=p()({},Object(i.A)(t)),u=s.type,c=s.properties,l=s.additionalProperties,f=s.items,d=s.example,m=a.includeReadOnly,v=a.includeWriteOnly,g=s.default,y={},b={},_=t.xml,w=_.name,x=_.prefix,E=_.namespace,S=s.enum;if(!u)if(c||l)u="object";else{if(!f)return;u="array"}if(n=(x?x+":":"")+(w=w||"notagname"),E){var C=x?"xmlns:"+x:"xmlns";b[C]=E}if("array"===u&&f){if(f.xml=f.xml||_||{},f.xml.name=f.xml.name||_.name,_.wrapped)return y[n]=[],o()(d)?d.forEach(function(t){f.example=t,y[n].push(e(f,a))}):o()(g)?g.forEach(function(t){f.default=t,y[n].push(e(f,a))}):y[n]=[e(f,a)],b&&y[n].push({_attr:b}),y;var k=[];return o()(d)?(d.forEach(function(t){f.example=t,k.push(e(f,a))}),k):o()(g)?(g.forEach(function(t){f.default=t,k.push(e(f,a))}),k):e(f,a)}if("object"===u){var O=Object(i.A)(c);for(var A in y[n]=[],d=d||{},O)if(O.hasOwnProperty(A)&&(!O[A].readOnly||m)&&(!O[A].writeOnly||v))if(O[A].xml=O[A].xml||{},O[A].xml.attribute){var T=o()(O[A].enum)&&O[A].enum[0],j=O[A].example,P=O[A].default;b[O[A].xml.name||A]=void 0!==j&&j||void 0!==d[A]&&d[A]||void 0!==P&&P||T||h(O[A])}else{O[A].xml.name=O[A].xml.name||A,void 0===O[A].example&&void 0!==d[A]&&(O[A].example=d[A]);var I=e(O[A]);o()(I)?y[n]=y[n].concat(I):y[n].push(I)}return!0===l?y[n].push({additionalProp:"Anything can be here"}):l&&y[n].push({additionalProp:h(l)}),b&&y[n].push({_attr:b}),y}return r=void 0!==d?d:void 0!==g?g:o()(S)?S[0]:h(t),y[n]=b?[{_attr:b},r]:r,y};function g(e,t){var n=v(e,t);if(n)return s()(n,{declaration:!0,indent:"\t"})}var y=c()(g),b=c()(d)},function(e,t,n){"use strict";n.r(t),n.d(t,"UPDATE_CONFIGS",function(){return i}),n.d(t,"TOGGLE_CONFIGS",function(){return a}),n.d(t,"update",function(){return s}),n.d(t,"toggle",function(){return u}),n.d(t,"loaded",function(){return c});var r=n(2),o=n.n(r),i="configs_update",a="configs_toggle";function s(e,t){return{type:i,payload:o()({},e,t)}}function u(e){return{type:a,payload:e}}var c=function(){return function(){}}},function(e,t,n){"use strict";n.d(t,"a",function(){return a});var r=n(1),o=n.n(r),i=o.a.Set.of("type","format","items","default","maximum","exclusiveMaximum","minimum","exclusiveMinimum","maxLength","minLength","pattern","maxItems","minItems","uniqueItems","enum","multipleOf");function a(e){var t=(arguments.length>1&&void 0!==arguments[1]?arguments[1]:{}).isOAS3;if(!o.a.Map.isMap(e))return{schema:o.a.Map(),parameterContentMediaType:null};if(!t)return"body"===e.get("in")?{schema:e.get("schema",o.a.Map()),parameterContentMediaType:null}:{schema:e.filter(function(e,t){return i.includes(t)}),parameterContentMediaType:null};if(e.get("content")){var n=e.get("content",o.a.Map({})).keySeq().first();return{schema:e.getIn(["content",n,"schema"],o.a.Map()),parameterContentMediaType:n}}return{schema:e.get("schema",o.a.Map()),parameterContentMediaType:null}}},function(e,t,n){e.exports=n(781)},function(e,t,n){"use strict";n.r(t);var r=n(469),o="object"==typeof self&&self&&self.Object===Object&&self,i=(r.a||o||Function("return this")()).Symbol,a=Object.prototype,s=a.hasOwnProperty,u=a.toString,c=i?i.toStringTag:void 0;var l=function(e){var t=s.call(e,c),n=e[c];try{e[c]=void 0;var r=!0}catch(e){}var o=u.call(e);return r&&(t?e[c]=n:delete e[c]),o},p=Object.prototype.toString;var f=function(e){return p.call(e)},h="[object Null]",d="[object Undefined]",m=i?i.toStringTag:void 0;var v=function(e){return null==e?void 0===e?d:h:m&&m in Object(e)?l(e):f(e)};var g=function(e,t){return function(n){return e(t(n))}}(Object.getPrototypeOf,Object);var y=function(e){return null!=e&&"object"==typeof e},b="[object Object]",_=Function.prototype,w=Object.prototype,x=_.toString,E=w.hasOwnProperty,S=x.call(Object);var C=function(e){if(!y(e)||v(e)!=b)return!1;var t=g(e);if(null===t)return!0;var n=E.call(t,"constructor")&&t.constructor;return"function"==typeof n&&n instanceof n&&x.call(n)==S},k=n(330),O={INIT:"@@redux/INIT"};function A(e,t,n){var r;if("function"==typeof t&&void 0===n&&(n=t,t=void 0),void 0!==n){if("function"!=typeof n)throw new Error("Expected the enhancer to be a function.");return n(A)(e,t)}if("function"!=typeof e)throw new Error("Expected the reducer to be a function.");var o=e,i=t,a=[],s=a,u=!1;function c(){s===a&&(s=a.slice())}function l(){return i}function p(e){if("function"!=typeof e)throw new Error("Expected listener to be a function.");var t=!0;return c(),s.push(e),function(){if(t){t=!1,c();var n=s.indexOf(e);s.splice(n,1)}}}function f(e){if(!C(e))throw new Error("Actions must be plain objects. Use custom middleware for async actions.");if(void 0===e.type)throw new Error('Actions may not have an undefined "type" property. Have you misspelled a constant?');if(u)throw new Error("Reducers may not dispatch actions.");try{u=!0,i=o(i,e)}finally{u=!1}for(var t=a=s,n=0;n0&&void 0!==arguments[0]?arguments[0]:{},t=arguments[1];if(a)throw a;for(var r=!1,o={},s=0;s0?r:n)(e)}},function(e,t){e.exports={}},function(e,t,n){var r=n(348),o=n(215);e.exports=Object.keys||function(e){return r(e,o)}},function(e,t){var n={}.toString;e.exports=function(e){return n.call(e).slice(8,-1)}},function(e,t){e.exports=!0},function(e,t){e.exports=function(e){if("function"!=typeof e)throw TypeError(e+" is not a function!");return e}},function(e,t){e.exports=function(e,t){return{enumerable:!(1&e),configurable:!(2&e),writable:!(4&e),value:t}}},function(e,t,n){var r=n(49).f,o=n(75),i=n(34)("toStringTag");e.exports=function(e,t,n){e&&!o(e=n?e:e.prototype,i)&&r(e,i,{configurable:!0,value:t})}},function(e,t,n){var r=n(159)("meta"),o=n(43),i=n(75),a=n(49).f,s=0,u=Object.isExtensible||function(){return!0},c=!n(82)(function(){return u(Object.preventExtensions({}))}),l=function(e){a(e,r,{value:{i:"O"+ ++s,w:{}}})},p=e.exports={KEY:r,NEED:!1,fastKey:function(e,t){if(!o(e))return"symbol"==typeof e?e:("string"==typeof e?"S":"P")+e;if(!i(e,r)){if(!u(e))return"F";if(!t)return"E";l(e)}return e[r].i},getWeak:function(e,t){if(!i(e,r)){if(!u(e))return!0;if(!t)return!1;l(e)}return e[r].w},onFreeze:function(e){return c&&p.NEED&&u(e)&&!i(e,r)&&l(e),e}}},function(e,t,n){"use strict";e.exports=function(e){for(var t=arguments.length-1,n="Minified React error #"+e+"; visit http://facebook.github.io/react/docs/error-decoder.html?invariant="+e,r=0;r1&&void 0!==arguments[1]?arguments[1]:[],n={arrayBehaviour:(arguments.length>2&&void 0!==arguments[2]?arguments[2]:{}).arrayBehaviour||"replace"},r=t.map(function(e){return e||{}}),i=e||{},c=0;c1?t-1:0),r=1;r")}),p=function(){var e=/(?:)/,t=e.exec;e.exec=function(){return t.apply(this,arguments)};var n="ab".split(e);return 2===n.length&&"a"===n[0]&&"b"===n[1]}();e.exports=function(e,t,n){var f=s(e),h=!i(function(){var t={};return t[f]=function(){return 7},7!=""[e](t)}),d=h?!i(function(){var t=!1,n=/a/;return n.exec=function(){return t=!0,null},"split"===e&&(n.constructor={},n.constructor[c]=function(){return n}),n[f](""),!t}):void 0;if(!h||!d||"replace"===e&&!l||"split"===e&&!p){var m=/./[f],v=n(a,f,""[e],function(e,t,n,r,o){return t.exec===u?h&&!o?{done:!0,value:m.call(t,n,r)}:{done:!0,value:e.call(n,t,r)}:{done:!1}}),g=v[0],y=v[1];r(String.prototype,e,g),o(RegExp.prototype,f,2==t?function(e,t){return y.call(e,this,t)}:function(e){return y.call(e,this)})}}},function(e,t,n){var r=n(212),o=Math.min;e.exports=function(e){return e>0?o(r(e),9007199254740991):0}},function(e,t){var n=0,r=Math.random();e.exports=function(e){return"Symbol(".concat(void 0===e?"":e,")_",(++n+r).toString(36))}},function(e,t,n){var r=n(46),o=n(350),i=n(215),a=n(213)("IE_PROTO"),s=function(){},u=function(){var e,t=n(217)("iframe"),r=i.length;for(t.style.display="none",n(351).appendChild(t),t.src="javascript:",(e=t.contentWindow.document).open(),e.write("
+
+  
+  
+    
+ + + +
+
+
+
+ + +
+ + + + + +
+

Questions and Feedback

+ + +

While we have given the current feature set a lot of consideration, we cannot understand all your constraints. +Let us know what you are thinking. +Your questions and feedback help us.

+

Ideas

+
    +
  • You want to more about how something works?
  • +
  • You want to know why something works the way it does?
  • +
  • How to integrate with your favorite library?
  • +
  • What is a good pattern for expressing your particular problem?
  • +
  • Do you have an interesting use case?
  • +
  • Have you hit a barrier that makes it impossible to use?
  • +
+

Channels

+

At the moment we would like to avoid creating yet one more community you need to sign up for. +Use these existing channels instead.

+

GitHub

+

For Javascript/Typescript related questions ask on our Github Page:

+

bgjs Github

+

For questions or feedback related to this documentation we have a separate Github Repository:

+

bgdocs Github

+

Stack Overflow

+

We will monitor StackOverflow for Behavior Graph related questions if you tag them with behavior-graph.

+ + + + +
+ + +
+
+
+ +
+
+
+
+ +
+
+ +
+
+ © 2022 Yahoo All Rights Reserved + + + + +
+
+
+
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/typescript/quickstart/index.html b/docs/typescript/quickstart/index.html new file mode 100644 index 0000000..51c6e66 --- /dev/null +++ b/docs/typescript/quickstart/index.html @@ -0,0 +1,345 @@ + + + + + + + + + + + + + + + + + + + + +Quick Start | Behavior Graph + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+
+
+
+ + +
+ + + + + +
+

Quick Start

+ + +

Using Behavior Graph is as simple as downloading it via your preferred format and importing it into your source.

+

Downloading

+

NPM

+

Behavior Graph is hosted on NPM @ behavior-graph.

+

You may add it as a dependency in your project’s package.json manually or install it via the shell +It supports both CommonJS and module imports.

+
npm install behavior-graph
+

Please search the web for any help using npm.

+

GitHub

+

Behavior Graph is available in source form via Github @ yahoo/bgjs.

+

Javascript CDNs

+

Behavior Graph is also available via a number of popular CDN Services. +You may prefer to use these when importing directly into the browser.

+ +

Importing

+

Javascript imports require some knowledge of your environment which is beyond the scope of this guide.

+

For modern environments:

+

Node: import * as bg from behavior-graph

+

or

+

Browser: import * as bg from "https://cdn.skypack.dev/behavior-graph";

+

Behavior Graph is also available as an IIFE which you can include as a script tag directly into the browser.

+

<script src="https://cdn.jsdelivr.net/npm/behavior-graph/lib/behavior-graph.min.js"></script>

+

The default export name is bg when using this method.

+

Quicker Start

+

To start exploring feel free to use any of the following which have been preconfigured to use Behavior Graph.

+ +

Coding

+

Typescript or Javascript

+

Behavior-Graph is written in Typescript. +It is usable directly from Javascript or Typescript code. +Type declaration files are provided for all APIs.

+

Hello, World!

+

Once you’ve set up your environment, type in the following to see the magic inside the Javascript console.

+
let g = new bg.Graph();
+let e = new bg.Extent(g);
+let m1 = e.moment();
+e.behavior()
+  .demands(m1)
+  .runs(() => {
+  	console.log('Hello, World!')
+  });
+e.addToGraphWithAction();
+m1.updateWithAction();
+

If this does not work, double check your imports and your environment.

+

Tutorials

+

It is unlikely you will get very far with Behavior Graph without working through a tutorial. +Please spend some time with them to practice writing Behavior Graph code. +They don’t take very long, and you will be mentally stimulated and spiritually rewarded for your time.

+ + + + +
+ + +
+
+
+ +
+
+
+
+ +
+
+ +
+
+ © 2022 Yahoo All Rights Reserved + + + + +
+
+
+
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/typescript/relatedwork/index.html b/docs/typescript/relatedwork/index.html new file mode 100644 index 0000000..1873a11 --- /dev/null +++ b/docs/typescript/relatedwork/index.html @@ -0,0 +1,289 @@ + + + + + + + + + + + + + + + + + + + + +Related Work | Behavior Graph + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+
+
+
+ + +
+ + + + + +
+

Related Work

+ + +

We acknowledge the hard work and incredible contributions from everyone below.

+ + + + + +
+ + +
+
+
+ +
+
+
+
+ +
+
+ +
+
+ © 2022 Yahoo All Rights Reserved + + + + +
+
+
+
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/typescript/robots.txt b/docs/typescript/robots.txt new file mode 100644 index 0000000..4f9540b --- /dev/null +++ b/docs/typescript/robots.txt @@ -0,0 +1 @@ +User-agent: * \ No newline at end of file diff --git a/docs/typescript/scss/main.min.704093cd1a56f37fd00dc35c7125fced09d88d60c92d59965b30c8c0eeef1cd5.css b/docs/typescript/scss/main.min.704093cd1a56f37fd00dc35c7125fced09d88d60c92d59965b30c8c0eeef1cd5.css new file mode 100644 index 0000000..934680a --- /dev/null +++ b/docs/typescript/scss/main.min.704093cd1a56f37fd00dc35c7125fced09d88d60c92d59965b30c8c0eeef1cd5.css @@ -0,0 +1,7 @@ +@import "https://fonts.googleapis.com/css?family=Open+Sans:300,300i,400,400i,700,700i&display=swap";@import "https://cdn.jsdelivr.net/gh/rastikerdar/vazir-font@v27.0.1/dist/font-face.css";@import "https://fonts.googleapis.com/css2?family=Rubik:wght@300;400;500;600;700&display=swap";@import "https://fonts.googleapis.com/css2?family=Tajawal:wght@300;400;500;700&display=swap";@fa-font-path:"../webfonts";/*!* Bootstrap v4.6.1 (https://getbootstrap.com/) +* Copyright 2011-2021 The Bootstrap Authors +* Copyright 2011-2021 Twitter, Inc. +* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)*/:root{--blue:#72A1E5;--indigo:#6610f2;--purple:#6f42c1;--pink:#e83e8c;--red:#dc3545;--orange:#BA5A31;--yellow:#ffc107;--green:#28a745;--teal:#20c997;--cyan:#17a2b8;--white:#fff;--gray:#797676;--gray-dark:#333;--primary:#30638E;--secondary:#FFA630;--success:#3772FF;--info:#C0E0DE;--warning:#ED6A5A;--danger:#ED6A5A;--light:#D3F3EE;--dark:#403F4C;--breakpoint-xs:0;--breakpoint-sm:576px;--breakpoint-md:768px;--breakpoint-lg:992px;--breakpoint-xl:1200px;--font-family-sans-serif:"Open Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";--font-family-monospace:SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace}*,*::before,*::after{box-sizing:border-box}html{font-family:sans-serif;line-height:1.15;-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:transparent}article,aside,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}body{margin:0;font-family:open sans,-apple-system,BlinkMacSystemFont,segoe ui,Roboto,helvetica neue,Arial,sans-serif,apple color emoji,segoe ui emoji,segoe ui symbol;font-size:1rem;font-weight:400;line-height:1.5;color:#222;text-align:left;background-color:#fff}[tabindex="-1"]:focus:not(:focus-visible){outline:0!important}hr{box-sizing:content-box;height:0;overflow:visible}h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem}p{margin-top:0;margin-bottom:1rem}abbr[title],abbr[data-original-title]{text-decoration:underline;-webkit-text-decoration:underline dotted;text-decoration:underline dotted;cursor:help;border-bottom:0;-webkit-text-decoration-skip-ink:none;text-decoration-skip-ink:none}address{margin-bottom:1rem;font-style:normal;line-height:inherit}ol,ul,dl{margin-top:0;margin-bottom:1rem}ol ol,ul ul,ol ul,ul ol{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}b,strong{font-weight:bolder}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:#3176d9;text-decoration:none;background-color:transparent}a:hover{color:#1e53a0;text-decoration:none}a:not([href]):not([class]){color:inherit;text-decoration:none}a:not([href]):not([class]):hover{color:inherit;text-decoration:none}pre,code,kbd,samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,liberation mono,courier new,monospace;font-size:1em}pre{margin-top:0;margin-bottom:1rem;overflow:auto;-ms-overflow-style:scrollbar}figure{margin:0 0 1rem}img{vertical-align:middle;border-style:none}svg{overflow:hidden;vertical-align:middle}table{border-collapse:collapse}caption{padding-top:.75rem;padding-bottom:.75rem;color:#797676;text-align:left;caption-side:bottom}th{text-align:inherit;text-align:-webkit-match-parent}label{display:inline-block;margin-bottom:.5rem}button{border-radius:0}button:focus:not(:focus-visible){outline:0}input,button,select,optgroup,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,input{overflow:visible}button,select{text-transform:none}[role=button]{cursor:pointer}select{word-wrap:normal}button,[type=button],[type=reset],[type=submit]{-webkit-appearance:button}button:not(:disabled),[type=button]:not(:disabled),[type=reset]:not(:disabled),[type=submit]:not(:disabled){cursor:pointer}button::-moz-focus-inner,[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner{padding:0;border-style:none}input[type=radio],input[type=checkbox]{box-sizing:border-box;padding:0}textarea{overflow:auto;resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{display:block;width:100%;max-width:100%;padding:0;margin-bottom:.5rem;font-size:1.5rem;line-height:inherit;color:inherit;white-space:normal}progress{vertical-align:baseline}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{outline-offset:-2px;-webkit-appearance:none}[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}output{display:inline-block}summary{display:list-item;cursor:pointer}template{display:none}[hidden]{display:none!important}h1,h2,h3,h4,h5,h6,.h1,.h2,.h3,.h4,.h5,.h6{margin-bottom:.5rem;font-weight:500;line-height:1.2}h1,.h1{font-size:2.25rem}h2,.h2{font-size:2rem}h3,.h3{font-size:1.5rem}h4,.h4{font-size:1.35rem}h5,.h5{font-size:1.15rem}h6,.h6{font-size:1rem}.lead{font-size:1.25rem;font-weight:300}.display-1{font-size:3rem;font-weight:700;line-height:1.2}.display-2{font-size:2.5rem;font-weight:700;line-height:1.2}.display-3{font-size:2rem;font-weight:700;line-height:1.2}.display-4{font-size:1.75rem;font-weight:700;line-height:1.2}hr{margin-top:1rem;margin-bottom:1rem;border:0;border-top:1px solid rgba(0,0,0,.1)}small,.small{font-size:80%;font-weight:400}mark,.mark{padding:.2em;background-color:#fcf8e3}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;list-style:none}.list-inline-item{display:inline-block}.list-inline-item:not(:last-child){margin-right:.5rem}.initialism{font-size:90%;text-transform:uppercase}.blockquote{margin-bottom:1rem;font-size:1.25rem}.blockquote-footer{display:block;font-size:80%;color:#797676}.blockquote-footer::before{content:"\2014\00A0"}.img-fluid,.td-content img{max-width:100%;height:auto}.img-thumbnail{padding:.25rem;background-color:#fff;border:1px solid #dee2e6;border-radius:.25rem;box-shadow:0 1px 2px rgba(0,0,0,.075);max-width:100%;height:auto}.figure{display:inline-block}.figure-img{margin-bottom:.5rem;line-height:1}.figure-caption{font-size:90%;color:#797676}code{font-size:87.5%;color:#c97300;word-wrap:break-word}a>code{color:inherit}kbd{padding:.2rem .4rem;font-size:87.5%;color:#fff;background-color:#222;border-radius:.2rem;box-shadow:inset 0 -.1rem rgba(0,0,0,.25)}kbd kbd{padding:0;font-size:100%;font-weight:700;box-shadow:none}pre{display:block;font-size:87.5%;color:#222}pre code{font-size:inherit;color:inherit;word-break:normal}.pre-scrollable{max-height:340px;overflow-y:scroll}.container,.container-fluid,.container-xl,.container-lg,.container-md,.container-sm{width:100%;padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}@media(min-width:576px){.container-sm,.container{max-width:540px}}@media(min-width:768px){.container-md,.container-sm,.container{max-width:720px}}@media(min-width:992px){.container-lg,.container-md,.container-sm,.container{max-width:960px}}@media(min-width:1200px){.container-xl,.container-lg,.container-md,.container-sm,.container{max-width:1140px}}.row{display:flex;flex-wrap:wrap;margin-right:-15px;margin-left:-15px}.no-gutters{margin-right:0;margin-left:0}.no-gutters>.col,.no-gutters>[class*=col-]{padding-right:0;padding-left:0}.col-xl,.col-xl-auto,.col-xl-12,.col-xl-11,.col-xl-10,.col-xl-9,.col-xl-8,.col-xl-7,.col-xl-6,.col-xl-5,.col-xl-4,.col-xl-3,.col-xl-2,.col-xl-1,.col-lg,.col-lg-auto,.col-lg-12,.col-lg-11,.col-lg-10,.col-lg-9,.col-lg-8,.col-lg-7,.col-lg-6,.col-lg-5,.col-lg-4,.col-lg-3,.col-lg-2,.col-lg-1,.col-md,.col-md-auto,.col-md-12,.col-md-11,.col-md-10,.col-md-9,.col-md-8,.col-md-7,.col-md-6,.col-md-5,.col-md-4,.col-md-3,.col-md-2,.col-md-1,.col-sm,.col-sm-auto,.col-sm-12,.col-sm-11,.col-sm-10,.col-sm-9,.col-sm-8,.col-sm-7,.col-sm-6,.col-sm-5,.col-sm-4,.col-sm-3,.col-sm-2,.col-sm-1,.col,.col-auto,.col-12,.col-11,.col-10,.col-9,.col-8,.col-7,.col-6,.col-5,.col-4,.col-3,.col-2,.col-1{position:relative;width:100%;padding-right:15px;padding-left:15px}.col{flex-basis:0;flex-grow:1;max-width:100%}.row-cols-1>*{flex:0 0 100%;max-width:100%}.row-cols-2>*{flex:0 0 50%;max-width:50%}.row-cols-3>*{flex:0 0 33.33333333%;max-width:33.33333333%}.row-cols-4>*{flex:0 0 25%;max-width:25%}.row-cols-5>*{flex:0 0 20%;max-width:20%}.row-cols-6>*{flex:0 0 16.66666667%;max-width:16.66666667%}.col-auto{flex:none;width:auto;max-width:100%}.col-1{flex:0 0 8.33333333%;max-width:8.33333333%}.col-2{flex:0 0 16.66666667%;max-width:16.66666667%}.col-3{flex:0 0 25%;max-width:25%}.col-4{flex:0 0 33.33333333%;max-width:33.33333333%}.col-5{flex:0 0 41.66666667%;max-width:41.66666667%}.col-6{flex:0 0 50%;max-width:50%}.col-7{flex:0 0 58.33333333%;max-width:58.33333333%}.col-8{flex:0 0 66.66666667%;max-width:66.66666667%}.col-9{flex:0 0 75%;max-width:75%}.col-10{flex:0 0 83.33333333%;max-width:83.33333333%}.col-11{flex:0 0 91.66666667%;max-width:91.66666667%}.col-12{flex:0 0 100%;max-width:100%}.order-first{order:-1}.order-last{order:13}.order-0{order:0}.order-1{order:1}.order-2{order:2}.order-3{order:3}.order-4{order:4}.order-5{order:5}.order-6{order:6}.order-7{order:7}.order-8{order:8}.order-9{order:9}.order-10{order:10}.order-11{order:11}.order-12{order:12}.offset-1{margin-left:8.33333333%}.offset-2{margin-left:16.66666667%}.offset-3{margin-left:25%}.offset-4{margin-left:33.33333333%}.offset-5{margin-left:41.66666667%}.offset-6{margin-left:50%}.offset-7{margin-left:58.33333333%}.offset-8{margin-left:66.66666667%}.offset-9{margin-left:75%}.offset-10{margin-left:83.33333333%}.offset-11{margin-left:91.66666667%}@media(min-width:576px){.col-sm{flex-basis:0;flex-grow:1;max-width:100%}.row-cols-sm-1>*{flex:0 0 100%;max-width:100%}.row-cols-sm-2>*{flex:0 0 50%;max-width:50%}.row-cols-sm-3>*{flex:0 0 33.33333333%;max-width:33.33333333%}.row-cols-sm-4>*{flex:0 0 25%;max-width:25%}.row-cols-sm-5>*{flex:0 0 20%;max-width:20%}.row-cols-sm-6>*{flex:0 0 16.66666667%;max-width:16.66666667%}.col-sm-auto{flex:none;width:auto;max-width:100%}.col-sm-1{flex:0 0 8.33333333%;max-width:8.33333333%}.col-sm-2{flex:0 0 16.66666667%;max-width:16.66666667%}.col-sm-3{flex:0 0 25%;max-width:25%}.col-sm-4{flex:0 0 33.33333333%;max-width:33.33333333%}.col-sm-5{flex:0 0 41.66666667%;max-width:41.66666667%}.col-sm-6{flex:0 0 50%;max-width:50%}.col-sm-7{flex:0 0 58.33333333%;max-width:58.33333333%}.col-sm-8{flex:0 0 66.66666667%;max-width:66.66666667%}.col-sm-9{flex:0 0 75%;max-width:75%}.col-sm-10{flex:0 0 83.33333333%;max-width:83.33333333%}.col-sm-11{flex:0 0 91.66666667%;max-width:91.66666667%}.col-sm-12{flex:0 0 100%;max-width:100%}.order-sm-first{order:-1}.order-sm-last{order:13}.order-sm-0{order:0}.order-sm-1{order:1}.order-sm-2{order:2}.order-sm-3{order:3}.order-sm-4{order:4}.order-sm-5{order:5}.order-sm-6{order:6}.order-sm-7{order:7}.order-sm-8{order:8}.order-sm-9{order:9}.order-sm-10{order:10}.order-sm-11{order:11}.order-sm-12{order:12}.offset-sm-0{margin-left:0}.offset-sm-1{margin-left:8.33333333%}.offset-sm-2{margin-left:16.66666667%}.offset-sm-3{margin-left:25%}.offset-sm-4{margin-left:33.33333333%}.offset-sm-5{margin-left:41.66666667%}.offset-sm-6{margin-left:50%}.offset-sm-7{margin-left:58.33333333%}.offset-sm-8{margin-left:66.66666667%}.offset-sm-9{margin-left:75%}.offset-sm-10{margin-left:83.33333333%}.offset-sm-11{margin-left:91.66666667%}}@media(min-width:768px){.col-md{flex-basis:0;flex-grow:1;max-width:100%}.row-cols-md-1>*{flex:0 0 100%;max-width:100%}.row-cols-md-2>*{flex:0 0 50%;max-width:50%}.row-cols-md-3>*{flex:0 0 33.33333333%;max-width:33.33333333%}.row-cols-md-4>*{flex:0 0 25%;max-width:25%}.row-cols-md-5>*{flex:0 0 20%;max-width:20%}.row-cols-md-6>*{flex:0 0 16.66666667%;max-width:16.66666667%}.col-md-auto{flex:none;width:auto;max-width:100%}.col-md-1{flex:0 0 8.33333333%;max-width:8.33333333%}.col-md-2{flex:0 0 16.66666667%;max-width:16.66666667%}.col-md-3{flex:0 0 25%;max-width:25%}.col-md-4{flex:0 0 33.33333333%;max-width:33.33333333%}.col-md-5{flex:0 0 41.66666667%;max-width:41.66666667%}.col-md-6{flex:0 0 50%;max-width:50%}.col-md-7{flex:0 0 58.33333333%;max-width:58.33333333%}.col-md-8{flex:0 0 66.66666667%;max-width:66.66666667%}.col-md-9{flex:0 0 75%;max-width:75%}.col-md-10{flex:0 0 83.33333333%;max-width:83.33333333%}.col-md-11{flex:0 0 91.66666667%;max-width:91.66666667%}.col-md-12{flex:0 0 100%;max-width:100%}.order-md-first{order:-1}.order-md-last{order:13}.order-md-0{order:0}.order-md-1{order:1}.order-md-2{order:2}.order-md-3{order:3}.order-md-4{order:4}.order-md-5{order:5}.order-md-6{order:6}.order-md-7{order:7}.order-md-8{order:8}.order-md-9{order:9}.order-md-10{order:10}.order-md-11{order:11}.order-md-12{order:12}.offset-md-0{margin-left:0}.offset-md-1{margin-left:8.33333333%}.offset-md-2{margin-left:16.66666667%}.offset-md-3{margin-left:25%}.offset-md-4{margin-left:33.33333333%}.offset-md-5{margin-left:41.66666667%}.offset-md-6{margin-left:50%}.offset-md-7{margin-left:58.33333333%}.offset-md-8{margin-left:66.66666667%}.offset-md-9{margin-left:75%}.offset-md-10{margin-left:83.33333333%}.offset-md-11{margin-left:91.66666667%}}@media(min-width:992px){.col-lg{flex-basis:0;flex-grow:1;max-width:100%}.row-cols-lg-1>*{flex:0 0 100%;max-width:100%}.row-cols-lg-2>*{flex:0 0 50%;max-width:50%}.row-cols-lg-3>*{flex:0 0 33.33333333%;max-width:33.33333333%}.row-cols-lg-4>*{flex:0 0 25%;max-width:25%}.row-cols-lg-5>*{flex:0 0 20%;max-width:20%}.row-cols-lg-6>*{flex:0 0 16.66666667%;max-width:16.66666667%}.col-lg-auto{flex:none;width:auto;max-width:100%}.col-lg-1{flex:0 0 8.33333333%;max-width:8.33333333%}.col-lg-2{flex:0 0 16.66666667%;max-width:16.66666667%}.col-lg-3{flex:0 0 25%;max-width:25%}.col-lg-4{flex:0 0 33.33333333%;max-width:33.33333333%}.col-lg-5{flex:0 0 41.66666667%;max-width:41.66666667%}.col-lg-6{flex:0 0 50%;max-width:50%}.col-lg-7{flex:0 0 58.33333333%;max-width:58.33333333%}.col-lg-8{flex:0 0 66.66666667%;max-width:66.66666667%}.col-lg-9{flex:0 0 75%;max-width:75%}.col-lg-10{flex:0 0 83.33333333%;max-width:83.33333333%}.col-lg-11{flex:0 0 91.66666667%;max-width:91.66666667%}.col-lg-12{flex:0 0 100%;max-width:100%}.order-lg-first{order:-1}.order-lg-last{order:13}.order-lg-0{order:0}.order-lg-1{order:1}.order-lg-2{order:2}.order-lg-3{order:3}.order-lg-4{order:4}.order-lg-5{order:5}.order-lg-6{order:6}.order-lg-7{order:7}.order-lg-8{order:8}.order-lg-9{order:9}.order-lg-10{order:10}.order-lg-11{order:11}.order-lg-12{order:12}.offset-lg-0{margin-left:0}.offset-lg-1{margin-left:8.33333333%}.offset-lg-2{margin-left:16.66666667%}.offset-lg-3{margin-left:25%}.offset-lg-4{margin-left:33.33333333%}.offset-lg-5{margin-left:41.66666667%}.offset-lg-6{margin-left:50%}.offset-lg-7{margin-left:58.33333333%}.offset-lg-8{margin-left:66.66666667%}.offset-lg-9{margin-left:75%}.offset-lg-10{margin-left:83.33333333%}.offset-lg-11{margin-left:91.66666667%}}@media(min-width:1200px){.col-xl{flex-basis:0;flex-grow:1;max-width:100%}.row-cols-xl-1>*{flex:0 0 100%;max-width:100%}.row-cols-xl-2>*{flex:0 0 50%;max-width:50%}.row-cols-xl-3>*{flex:0 0 33.33333333%;max-width:33.33333333%}.row-cols-xl-4>*{flex:0 0 25%;max-width:25%}.row-cols-xl-5>*{flex:0 0 20%;max-width:20%}.row-cols-xl-6>*{flex:0 0 16.66666667%;max-width:16.66666667%}.col-xl-auto{flex:none;width:auto;max-width:100%}.col-xl-1{flex:0 0 8.33333333%;max-width:8.33333333%}.col-xl-2{flex:0 0 16.66666667%;max-width:16.66666667%}.col-xl-3{flex:0 0 25%;max-width:25%}.col-xl-4{flex:0 0 33.33333333%;max-width:33.33333333%}.col-xl-5{flex:0 0 41.66666667%;max-width:41.66666667%}.col-xl-6{flex:0 0 50%;max-width:50%}.col-xl-7{flex:0 0 58.33333333%;max-width:58.33333333%}.col-xl-8{flex:0 0 66.66666667%;max-width:66.66666667%}.col-xl-9{flex:0 0 75%;max-width:75%}.col-xl-10{flex:0 0 83.33333333%;max-width:83.33333333%}.col-xl-11{flex:0 0 91.66666667%;max-width:91.66666667%}.col-xl-12{flex:0 0 100%;max-width:100%}.order-xl-first{order:-1}.order-xl-last{order:13}.order-xl-0{order:0}.order-xl-1{order:1}.order-xl-2{order:2}.order-xl-3{order:3}.order-xl-4{order:4}.order-xl-5{order:5}.order-xl-6{order:6}.order-xl-7{order:7}.order-xl-8{order:8}.order-xl-9{order:9}.order-xl-10{order:10}.order-xl-11{order:11}.order-xl-12{order:12}.offset-xl-0{margin-left:0}.offset-xl-1{margin-left:8.33333333%}.offset-xl-2{margin-left:16.66666667%}.offset-xl-3{margin-left:25%}.offset-xl-4{margin-left:33.33333333%}.offset-xl-5{margin-left:41.66666667%}.offset-xl-6{margin-left:50%}.offset-xl-7{margin-left:58.33333333%}.offset-xl-8{margin-left:66.66666667%}.offset-xl-9{margin-left:75%}.offset-xl-10{margin-left:83.33333333%}.offset-xl-11{margin-left:91.66666667%}}.table,.td-content>table,.td-box .row.section>table{width:100%;margin-bottom:1rem;color:#222}.table th,.td-content>table th,.td-box .row.section>table th,.table td,.td-content>table td,.td-box .row.section>table td{padding:.75rem;vertical-align:top;border-top:1px solid #dee2e6}.table thead th,.td-content>table thead th,.td-box .row.section>table thead th{vertical-align:bottom;border-bottom:2px solid #dee2e6}.table tbody+tbody,.td-content>table tbody+tbody,.td-box .row.section>table tbody+tbody{border-top:2px solid #dee2e6}.table-sm th,.table-sm td{padding:.3rem}.table-bordered{border:1px solid #dee2e6}.table-bordered th,.table-bordered td{border:1px solid #dee2e6}.table-bordered thead th,.table-bordered thead td{border-bottom-width:2px}.table-borderless th,.table-borderless td,.table-borderless thead th,.table-borderless tbody+tbody{border:0}.table-striped tbody tr:nth-of-type(odd),.td-content>table tbody tr:nth-of-type(odd),.td-box .row.section>table tbody tr:nth-of-type(odd){background-color:rgba(0,0,0,5%)}.table-hover tbody tr:hover{color:#222;background-color:rgba(0,0,0,.075)}.table-primary,.table-primary>th,.table-primary>td{background-color:#c5d3df}.table-primary th,.table-primary td,.table-primary thead th,.table-primary tbody+tbody{border-color:#93aec4}.table-hover .table-primary:hover{background-color:#b5c7d6}.table-hover .table-primary:hover>td,.table-hover .table-primary:hover>th{background-color:#b5c7d6}.table-secondary,.table-secondary>th,.table-secondary>td{background-color:#ffe6c5}.table-secondary th,.table-secondary td,.table-secondary thead th,.table-secondary tbody+tbody{border-color:#ffd193}.table-hover .table-secondary:hover{background-color:#ffdbac}.table-hover .table-secondary:hover>td,.table-hover .table-secondary:hover>th{background-color:#ffdbac}.table-success,.table-success>th,.table-success>td{background-color:#c7d8ff}.table-success th,.table-success td,.table-success thead th,.table-success tbody+tbody{border-color:#97b6ff}.table-hover .table-success:hover{background-color:#aec6ff}.table-hover .table-success:hover>td,.table-hover .table-success:hover>th{background-color:#aec6ff}.table-info,.table-info>th,.table-info>td{background-color:#edf6f6}.table-info th,.table-info td,.table-info thead th,.table-info tbody+tbody{border-color:#deefee}.table-hover .table-info:hover{background-color:#dceeee}.table-hover .table-info:hover>td,.table-hover .table-info:hover>th{background-color:#dceeee}.table-warning,.table-warning>th,.table-warning>td{background-color:#fad5d1}.table-warning th,.table-warning td,.table-warning thead th,.table-warning tbody+tbody{border-color:#f6b2a9}.table-hover .table-warning:hover{background-color:#f8c0ba}.table-hover .table-warning:hover>td,.table-hover .table-warning:hover>th{background-color:#f8c0ba}.table-danger,.table-danger>th,.table-danger>td{background-color:#fad5d1}.table-danger th,.table-danger td,.table-danger thead th,.table-danger tbody+tbody{border-color:#f6b2a9}.table-hover .table-danger:hover{background-color:#f8c0ba}.table-hover .table-danger:hover>td,.table-hover .table-danger:hover>th{background-color:#f8c0ba}.table-light,.table-light>th,.table-light>td{background-color:#f3fcfa}.table-light th,.table-light td,.table-light thead th,.table-light tbody+tbody{border-color:#e8f9f6}.table-hover .table-light:hover{background-color:#dff7f2}.table-hover .table-light:hover>td,.table-hover .table-light:hover>th{background-color:#dff7f2}.table-dark,.table-dark>th,.table-dark>td{background-color:#cac9cd}.table-dark th,.table-dark td,.table-dark thead th,.table-dark tbody+tbody{border-color:#9c9ba2}.table-hover .table-dark:hover{background-color:#bdbcc1}.table-hover .table-dark:hover>td,.table-hover .table-dark:hover>th{background-color:#bdbcc1}.table-active,.table-active>th,.table-active>td{background-color:rgba(0,0,0,.075)}.table-hover .table-active:hover{background-color:rgba(0,0,0,.075)}.table-hover .table-active:hover>td,.table-hover .table-active:hover>th{background-color:rgba(0,0,0,.075)}.table .thead-dark th,.td-content>table .thead-dark th,.td-box .row.section>table .thead-dark th{color:#fff;background-color:#333;border-color:#464646}.table .thead-light th,.td-content>table .thead-light th,.td-box .row.section>table .thead-light th{color:#495057;background-color:#eee;border-color:#dee2e6}.table-dark{color:#fff;background-color:#333}.table-dark th,.table-dark td,.table-dark thead th{border-color:#464646}.table-dark.table-bordered{border:0}.table-dark.table-striped tbody tr:nth-of-type(odd),.td-content>table.table-dark tbody tr:nth-of-type(odd),.td-box .row.section>table.table-dark tbody tr:nth-of-type(odd){background-color:rgba(255,255,255,5%)}.table-dark.table-hover tbody tr:hover{color:#fff;background-color:rgba(255,255,255,.075)}@media(max-width:575.98px){.table-responsive-sm{display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch}.table-responsive-sm>.table-bordered{border:0}}@media(max-width:767.98px){.table-responsive-md{display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch}.table-responsive-md>.table-bordered{border:0}}@media(max-width:991.98px){.table-responsive-lg{display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch}.table-responsive-lg>.table-bordered{border:0}}@media(max-width:1199.98px){.table-responsive-xl{display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch}.table-responsive-xl>.table-bordered{border:0}}.table-responsive,.td-content>table,.td-box .row.section>table{display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch}.table-responsive>.table-bordered,.td-content>table>.table-bordered,.td-box .row.section>table>.table-bordered{border:0}.form-control{display:block;width:100%;height:calc(1.5em + .75rem + 2px);padding:.375rem .75rem;font-size:1rem;font-weight:400;line-height:1.5;color:#495057;background-color:#fff;background-clip:padding-box;border:1px solid #ccc;border-radius:.25rem;box-shadow:inset 0 1px 1px rgba(0,0,0,.075);transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media(prefers-reduced-motion:reduce){.form-control{transition:none}}.form-control::-ms-expand{background-color:transparent;border:0}.form-control:focus{color:#495057;background-color:#fff;border-color:#6fa3ce;outline:0;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 0 .2rem rgba(48,99,142,.25)}.form-control::-moz-placeholder{color:#797676;opacity:1}.form-control:-ms-input-placeholder{color:#797676;opacity:1}.form-control::placeholder{color:#797676;opacity:1}.form-control:disabled,.form-control[readonly]{background-color:#eee;opacity:1}input[type=date].form-control,input[type=time].form-control,input[type=datetime-local].form-control,input[type=month].form-control{-webkit-appearance:none;-moz-appearance:none;appearance:none}select.form-control:-moz-focusring{color:transparent;text-shadow:0 0 0 #495057}select.form-control:focus::-ms-value{color:#495057;background-color:#fff}.form-control-file,.form-control-range{display:block;width:100%}.col-form-label{padding-top:calc(.375rem + 1px);padding-bottom:calc(.375rem + 1px);margin-bottom:0;font-size:inherit;line-height:1.5}.col-form-label-lg{padding-top:calc(.5rem + 1px);padding-bottom:calc(.5rem + 1px);font-size:1.25rem;line-height:1.5}.col-form-label-sm{padding-top:calc(.25rem + 1px);padding-bottom:calc(.25rem + 1px);font-size:.875rem;line-height:1.5}.form-control-plaintext{display:block;width:100%;padding:.375rem 0;margin-bottom:0;font-size:1rem;line-height:1.5;color:#222;background-color:transparent;border:solid transparent;border-width:1px 0}.form-control-plaintext.form-control-sm,.form-control-plaintext.form-control-lg{padding-right:0;padding-left:0}.form-control-sm{height:calc(1.5em + .5rem + 2px);padding:.25rem .5rem;font-size:.875rem;line-height:1.5;border-radius:.2rem}.form-control-lg{height:calc(1.5em + 1rem + 2px);padding:.5rem 1rem;font-size:1.25rem;line-height:1.5;border-radius:.3rem}select.form-control[size],select.form-control[multiple]{height:auto}textarea.form-control{height:auto}.form-group{margin-bottom:1rem}.form-text{display:block;margin-top:.25rem}.form-row{display:flex;flex-wrap:wrap;margin-right:-5px;margin-left:-5px}.form-row>.col,.form-row>[class*=col-]{padding-right:5px;padding-left:5px}.form-check{position:relative;display:block;padding-left:1.25rem}.form-check-input{position:absolute;margin-top:.3rem;margin-left:-1.25rem}.form-check-input[disabled]~.form-check-label,.form-check-input:disabled~.form-check-label{color:#797676}.form-check-label{margin-bottom:0}.form-check-inline{display:inline-flex;align-items:center;padding-left:0;margin-right:.75rem}.form-check-inline .form-check-input{position:static;margin-top:0;margin-right:.3125rem;margin-left:0}.valid-feedback{display:none;width:100%;margin-top:.25rem;font-size:80%;color:#3772ff}.valid-tooltip{position:absolute;top:100%;left:0;z-index:5;display:none;max-width:100%;padding:.25rem .5rem;margin-top:.1rem;font-size:.875rem;line-height:1.5;color:#fff;background-color:rgba(55,114,255,.9);border-radius:.25rem}.form-row>.col>.valid-tooltip,.form-row>[class*=col-]>.valid-tooltip{left:5px}.was-validated :valid~.valid-feedback,.was-validated :valid~.valid-tooltip,.is-valid~.valid-feedback,.is-valid~.valid-tooltip{display:block}.was-validated .form-control:valid,.form-control.is-valid{border-color:#3772ff;padding-right:calc(1.5em + .75rem)!important;background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='8' height='8' viewBox='0 0 8 8'%3e%3cpath fill='%233772FF' d='M2.3 6.73L.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e");background-repeat:no-repeat;background-position:right calc(.375em + .1875rem)center;background-size:calc(.75em + .375rem)calc(.75em + .375rem)}.was-validated .form-control:valid:focus,.form-control.is-valid:focus{border-color:#3772ff;box-shadow:0 0 0 .2rem rgba(55,114,255,.25)}.was-validated select.form-control:valid,select.form-control.is-valid{padding-right:3rem!important;background-position:right 1.5rem center}.was-validated textarea.form-control:valid,textarea.form-control.is-valid{padding-right:calc(1.5em + .75rem);background-position:top calc(.375em + .1875rem)right calc(.375em + .1875rem)}.was-validated .custom-select:valid,.custom-select.is-valid{border-color:#3772ff;padding-right:calc(.75em + 2.3125rem)!important;background:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='4' height='5' viewBox='0 0 4 5'%3e%3cpath fill='%23333' d='M2 0L0 2h4zm0 5L0 3h4z'/%3e%3c/svg%3e")right .75rem center/8px 10px no-repeat,#fff url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='8' height='8' viewBox='0 0 8 8'%3e%3cpath fill='%233772FF' d='M2.3 6.73L.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e")center right 1.75rem/calc(.75em + .375rem)calc(.75em + .375rem)no-repeat}.was-validated .custom-select:valid:focus,.custom-select.is-valid:focus{border-color:#3772ff;box-shadow:0 0 0 .2rem rgba(55,114,255,.25)}.was-validated .form-check-input:valid~.form-check-label,.form-check-input.is-valid~.form-check-label{color:#3772ff}.was-validated .form-check-input:valid~.valid-feedback,.was-validated .form-check-input:valid~.valid-tooltip,.form-check-input.is-valid~.valid-feedback,.form-check-input.is-valid~.valid-tooltip{display:block}.was-validated .custom-control-input:valid~.custom-control-label,.custom-control-input.is-valid~.custom-control-label{color:#3772ff}.was-validated .custom-control-input:valid~.custom-control-label::before,.custom-control-input.is-valid~.custom-control-label::before{border-color:#3772ff}.was-validated .custom-control-input:valid:checked~.custom-control-label::before,.custom-control-input.is-valid:checked~.custom-control-label::before{border-color:#6a96ff;background:#6a96ff linear-gradient(180deg,#80a6ff,#6a96ff)repeat-x}.was-validated .custom-control-input:valid:focus~.custom-control-label::before,.custom-control-input.is-valid:focus~.custom-control-label::before{box-shadow:0 0 0 .2rem rgba(55,114,255,.25)}.was-validated .custom-control-input:valid:focus:not(:checked)~.custom-control-label::before,.custom-control-input.is-valid:focus:not(:checked)~.custom-control-label::before{border-color:#3772ff}.was-validated .custom-file-input:valid~.custom-file-label,.custom-file-input.is-valid~.custom-file-label{border-color:#3772ff}.was-validated .custom-file-input:valid:focus~.custom-file-label,.custom-file-input.is-valid:focus~.custom-file-label{border-color:#3772ff;box-shadow:0 0 0 .2rem rgba(55,114,255,.25)}.invalid-feedback{display:none;width:100%;margin-top:.25rem;font-size:80%;color:#ed6a5a}.invalid-tooltip{position:absolute;top:100%;left:0;z-index:5;display:none;max-width:100%;padding:.25rem .5rem;margin-top:.1rem;font-size:.875rem;line-height:1.5;color:#fff;background-color:rgba(237,106,90,.9);border-radius:.25rem}.form-row>.col>.invalid-tooltip,.form-row>[class*=col-]>.invalid-tooltip{left:5px}.was-validated :invalid~.invalid-feedback,.was-validated :invalid~.invalid-tooltip,.is-invalid~.invalid-feedback,.is-invalid~.invalid-tooltip{display:block}.was-validated .form-control:invalid,.form-control.is-invalid{border-color:#ed6a5a;padding-right:calc(1.5em + .75rem)!important;background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' fill='none' stroke='%23ED6A5A' viewBox='0 0 12 12'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23ED6A5A' stroke='none'/%3e%3c/svg%3e");background-repeat:no-repeat;background-position:right calc(.375em + .1875rem)center;background-size:calc(.75em + .375rem)calc(.75em + .375rem)}.was-validated .form-control:invalid:focus,.form-control.is-invalid:focus{border-color:#ed6a5a;box-shadow:0 0 0 .2rem rgba(237,106,90,.25)}.was-validated select.form-control:invalid,select.form-control.is-invalid{padding-right:3rem!important;background-position:right 1.5rem center}.was-validated textarea.form-control:invalid,textarea.form-control.is-invalid{padding-right:calc(1.5em + .75rem);background-position:top calc(.375em + .1875rem)right calc(.375em + .1875rem)}.was-validated .custom-select:invalid,.custom-select.is-invalid{border-color:#ed6a5a;padding-right:calc(.75em + 2.3125rem)!important;background:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='4' height='5' viewBox='0 0 4 5'%3e%3cpath fill='%23333' d='M2 0L0 2h4zm0 5L0 3h4z'/%3e%3c/svg%3e")right .75rem center/8px 10px no-repeat,#fff url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' fill='none' stroke='%23ED6A5A' viewBox='0 0 12 12'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23ED6A5A' stroke='none'/%3e%3c/svg%3e")center right 1.75rem/calc(.75em + .375rem)calc(.75em + .375rem)no-repeat}.was-validated .custom-select:invalid:focus,.custom-select.is-invalid:focus{border-color:#ed6a5a;box-shadow:0 0 0 .2rem rgba(237,106,90,.25)}.was-validated .form-check-input:invalid~.form-check-label,.form-check-input.is-invalid~.form-check-label{color:#ed6a5a}.was-validated .form-check-input:invalid~.invalid-feedback,.was-validated .form-check-input:invalid~.invalid-tooltip,.form-check-input.is-invalid~.invalid-feedback,.form-check-input.is-invalid~.invalid-tooltip{display:block}.was-validated .custom-control-input:invalid~.custom-control-label,.custom-control-input.is-invalid~.custom-control-label{color:#ed6a5a}.was-validated .custom-control-input:invalid~.custom-control-label::before,.custom-control-input.is-invalid~.custom-control-label::before{border-color:#ed6a5a}.was-validated .custom-control-input:invalid:checked~.custom-control-label::before,.custom-control-input.is-invalid:checked~.custom-control-label::before{border-color:#f29488;background:#f29488 linear-gradient(180deg,#f4a49a,#f29488)repeat-x}.was-validated .custom-control-input:invalid:focus~.custom-control-label::before,.custom-control-input.is-invalid:focus~.custom-control-label::before{box-shadow:0 0 0 .2rem rgba(237,106,90,.25)}.was-validated .custom-control-input:invalid:focus:not(:checked)~.custom-control-label::before,.custom-control-input.is-invalid:focus:not(:checked)~.custom-control-label::before{border-color:#ed6a5a}.was-validated .custom-file-input:invalid~.custom-file-label,.custom-file-input.is-invalid~.custom-file-label{border-color:#ed6a5a}.was-validated .custom-file-input:invalid:focus~.custom-file-label,.custom-file-input.is-invalid:focus~.custom-file-label{border-color:#ed6a5a;box-shadow:0 0 0 .2rem rgba(237,106,90,.25)}.form-inline{display:flex;flex-flow:row wrap;align-items:center}.form-inline .form-check{width:100%}@media(min-width:576px){.form-inline label{display:flex;align-items:center;justify-content:center;margin-bottom:0}.form-inline .form-group{display:flex;flex:none;flex-flow:row wrap;align-items:center;margin-bottom:0}.form-inline .form-control{display:inline-block;width:auto;vertical-align:middle}.form-inline .form-control-plaintext{display:inline-block}.form-inline .input-group,.form-inline .custom-select{width:auto}.form-inline .form-check{display:flex;align-items:center;justify-content:center;width:auto;padding-left:0}.form-inline .form-check-input{position:relative;flex-shrink:0;margin-top:0;margin-right:.25rem;margin-left:0}.form-inline .custom-control{align-items:center;justify-content:center}.form-inline .custom-control-label{margin-bottom:0}}.btn{display:inline-block;font-weight:400;color:#222;text-align:center;vertical-align:middle;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;background-color:transparent;border:1px solid transparent;padding:.375rem .75rem;font-size:1rem;line-height:1.5;border-radius:.25rem;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media(prefers-reduced-motion:reduce){.btn{transition:none}}.btn:hover{color:#222;text-decoration:none}.btn:focus,.btn.focus{outline:0;box-shadow:0 0 0 .2rem rgba(48,99,142,.25)}.btn.disabled,.btn:disabled{opacity:.65;box-shadow:none}.btn:not(:disabled):not(.disabled){cursor:pointer}.btn:not(:disabled):not(.disabled):active,.btn:not(:disabled):not(.disabled).active{box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn:not(:disabled):not(.disabled):active:focus,.btn:not(:disabled):not(.disabled).active:focus{box-shadow:0 0 0 .2rem rgba(48,99,142,.25),inset 0 3px 5px rgba(0,0,0,.125)}a.btn.disabled,fieldset:disabled a.btn{pointer-events:none}.btn-primary{color:#fff;background:#30638e linear-gradient(180deg,#4f7a9f,#30638E)repeat-x;border-color:#30638e;box-shadow:inset 0 1px rgba(255,255,255,.15),0 1px 1px rgba(0,0,0,.075)}.btn-primary:hover{color:#fff;background:#264f71 linear-gradient(180deg,#476987,#264f71)repeat-x;border-color:#234868}.btn-primary:focus,.btn-primary.focus{color:#fff;background:#264f71 linear-gradient(180deg,#476987,#264f71)repeat-x;border-color:#234868;box-shadow:inset 0 1px rgba(255,255,255,.15),0 1px 1px rgba(0,0,0,.075),0 0 0 .2rem rgba(79,122,159,.5)}.btn-primary.disabled,.btn-primary:disabled{color:#fff;background-color:#30638e;border-color:#30638e;background-image:none}.btn-primary:not(:disabled):not(.disabled):active,.btn-primary:not(:disabled):not(.disabled).active,.show>.btn-primary.dropdown-toggle{color:#fff;background-color:#234868;background-image:none;border-color:#20425e}.btn-primary:not(:disabled):not(.disabled):active:focus,.btn-primary:not(:disabled):not(.disabled).active:focus,.show>.btn-primary.dropdown-toggle:focus{box-shadow:inset 0 3px 5px rgba(0,0,0,.125),0 0 0 .2rem rgba(79,122,159,.5)}.btn-secondary{color:#fff;background:#ffa630 linear-gradient(180deg,#ffb34f,#FFA630)repeat-x;border-color:#ffa630;box-shadow:inset 0 1px rgba(255,255,255,.15),0 1px 1px rgba(0,0,0,.075)}.btn-secondary:hover{color:#fff;background:#ff960a linear-gradient(180deg,#ffa52f,#ff960a)repeat-x;border-color:#fc9000}.btn-secondary:focus,.btn-secondary.focus{color:#fff;background:#ff960a linear-gradient(180deg,#ffa52f,#ff960a)repeat-x;border-color:#fc9000;box-shadow:inset 0 1px rgba(255,255,255,.15),0 1px 1px rgba(0,0,0,.075),0 0 0 .2rem rgba(255,179,79,.5)}.btn-secondary.disabled,.btn-secondary:disabled{color:#fff;background-color:#ffa630;border-color:#ffa630;background-image:none}.btn-secondary:not(:disabled):not(.disabled):active,.btn-secondary:not(:disabled):not(.disabled).active,.show>.btn-secondary.dropdown-toggle{color:#fff;background-color:#fc9000;background-image:none;border-color:#ef8800}.btn-secondary:not(:disabled):not(.disabled):active:focus,.btn-secondary:not(:disabled):not(.disabled).active:focus,.show>.btn-secondary.dropdown-toggle:focus{box-shadow:inset 0 3px 5px rgba(0,0,0,.125),0 0 0 .2rem rgba(255,179,79,.5)}.btn-success{color:#fff;background:#3772ff linear-gradient(180deg,#5587ff,#3772FF)repeat-x;border-color:#3772ff;box-shadow:inset 0 1px rgba(255,255,255,.15),0 1px 1px rgba(0,0,0,.075)}.btn-success:hover{color:#fff;background:#1157ff linear-gradient(180deg,#3470ff,#1157ff)repeat-x;border-color:#044eff}.btn-success:focus,.btn-success.focus{color:#fff;background:#1157ff linear-gradient(180deg,#3470ff,#1157ff)repeat-x;border-color:#044eff;box-shadow:inset 0 1px rgba(255,255,255,.15),0 1px 1px rgba(0,0,0,.075),0 0 0 .2rem rgba(85,135,255,.5)}.btn-success.disabled,.btn-success:disabled{color:#fff;background-color:#3772ff;border-color:#3772ff;background-image:none}.btn-success:not(:disabled):not(.disabled):active,.btn-success:not(:disabled):not(.disabled).active,.show>.btn-success.dropdown-toggle{color:#fff;background-color:#044eff;background-image:none;border-color:#0049f6}.btn-success:not(:disabled):not(.disabled):active:focus,.btn-success:not(:disabled):not(.disabled).active:focus,.show>.btn-success.dropdown-toggle:focus{box-shadow:inset 0 3px 5px rgba(0,0,0,.125),0 0 0 .2rem rgba(85,135,255,.5)}.btn-info{color:#222;background:#c0e0de linear-gradient(180deg,#c9e5e3,#C0E0DE)repeat-x;border-color:#c0e0de;box-shadow:inset 0 1px rgba(255,255,255,.15),0 1px 1px rgba(0,0,0,.075)}.btn-info:hover{color:#fff;background:#a6d3d1 linear-gradient(180deg,#b4dad8,#a6d3d1)repeat-x;border-color:#9ecfcc}.btn-info:focus,.btn-info.focus{color:#fff;background:#a6d3d1 linear-gradient(180deg,#b4dad8,#a6d3d1)repeat-x;border-color:#9ecfcc;box-shadow:inset 0 1px rgba(255,255,255,.15),0 1px 1px rgba(0,0,0,.075),0 0 0 .2rem rgba(168,196,194,.5)}.btn-info.disabled,.btn-info:disabled{color:#222;background-color:#c0e0de;border-color:#c0e0de;background-image:none}.btn-info:not(:disabled):not(.disabled):active,.btn-info:not(:disabled):not(.disabled).active,.show>.btn-info.dropdown-toggle{color:#fff;background-color:#9ecfcc;background-image:none;border-color:#95cbc8}.btn-info:not(:disabled):not(.disabled):active:focus,.btn-info:not(:disabled):not(.disabled).active:focus,.show>.btn-info.dropdown-toggle:focus{box-shadow:inset 0 3px 5px rgba(0,0,0,.125),0 0 0 .2rem rgba(168,196,194,.5)}.btn-warning{color:#fff;background:#ed6a5a linear-gradient(180deg,#f08073,#ED6A5A)repeat-x;border-color:#ed6a5a;box-shadow:inset 0 1px rgba(255,255,255,.15),0 1px 1px rgba(0,0,0,.075)}.btn-warning:hover{color:#fff;background:#e94b38 linear-gradient(180deg,#ed6655,#e94b38)repeat-x;border-color:#e8402c}.btn-warning:focus,.btn-warning.focus{color:#fff;background:#e94b38 linear-gradient(180deg,#ed6655,#e94b38)repeat-x;border-color:#e8402c;box-shadow:inset 0 1px rgba(255,255,255,.15),0 1px 1px rgba(0,0,0,.075),0 0 0 .2rem rgba(240,128,115,.5)}.btn-warning.disabled,.btn-warning:disabled{color:#fff;background-color:#ed6a5a;border-color:#ed6a5a;background-image:none}.btn-warning:not(:disabled):not(.disabled):active,.btn-warning:not(:disabled):not(.disabled).active,.show>.btn-warning.dropdown-toggle{color:#fff;background-color:#e8402c;background-image:none;border-color:#e73621}.btn-warning:not(:disabled):not(.disabled):active:focus,.btn-warning:not(:disabled):not(.disabled).active:focus,.show>.btn-warning.dropdown-toggle:focus{box-shadow:inset 0 3px 5px rgba(0,0,0,.125),0 0 0 .2rem rgba(240,128,115,.5)}.btn-danger{color:#fff;background:#ed6a5a linear-gradient(180deg,#f08073,#ED6A5A)repeat-x;border-color:#ed6a5a;box-shadow:inset 0 1px rgba(255,255,255,.15),0 1px 1px rgba(0,0,0,.075)}.btn-danger:hover{color:#fff;background:#e94b38 linear-gradient(180deg,#ed6655,#e94b38)repeat-x;border-color:#e8402c}.btn-danger:focus,.btn-danger.focus{color:#fff;background:#e94b38 linear-gradient(180deg,#ed6655,#e94b38)repeat-x;border-color:#e8402c;box-shadow:inset 0 1px rgba(255,255,255,.15),0 1px 1px rgba(0,0,0,.075),0 0 0 .2rem rgba(240,128,115,.5)}.btn-danger.disabled,.btn-danger:disabled{color:#fff;background-color:#ed6a5a;border-color:#ed6a5a;background-image:none}.btn-danger:not(:disabled):not(.disabled):active,.btn-danger:not(:disabled):not(.disabled).active,.show>.btn-danger.dropdown-toggle{color:#fff;background-color:#e8402c;background-image:none;border-color:#e73621}.btn-danger:not(:disabled):not(.disabled):active:focus,.btn-danger:not(:disabled):not(.disabled).active:focus,.show>.btn-danger.dropdown-toggle:focus{box-shadow:inset 0 3px 5px rgba(0,0,0,.125),0 0 0 .2rem rgba(240,128,115,.5)}.btn-light{color:#222;background:#d3f3ee linear-gradient(180deg,#daf5f1,#D3F3EE)repeat-x;border-color:#d3f3ee;box-shadow:inset 0 1px rgba(255,255,255,.15),0 1px 1px rgba(0,0,0,.075)}.btn-light:hover{color:#222;background:#b5ebe2 linear-gradient(180deg,#c0eee7,#b5ebe2)repeat-x;border-color:#abe8df}.btn-light:focus,.btn-light.focus{color:#222;background:#b5ebe2 linear-gradient(180deg,#c0eee7,#b5ebe2)repeat-x;border-color:#abe8df;box-shadow:inset 0 1px rgba(255,255,255,.15),0 1px 1px rgba(0,0,0,.075),0 0 0 .2rem rgba(184,212,207,.5)}.btn-light.disabled,.btn-light:disabled{color:#222;background-color:#d3f3ee;border-color:#d3f3ee;background-image:none}.btn-light:not(:disabled):not(.disabled):active,.btn-light:not(:disabled):not(.disabled).active,.show>.btn-light.dropdown-toggle{color:#222;background-color:#abe8df;background-image:none;border-color:#a1e5db}.btn-light:not(:disabled):not(.disabled):active:focus,.btn-light:not(:disabled):not(.disabled).active:focus,.show>.btn-light.dropdown-toggle:focus{box-shadow:inset 0 3px 5px rgba(0,0,0,.125),0 0 0 .2rem rgba(184,212,207,.5)}.btn-dark{color:#fff;background:#403f4c linear-gradient(180deg,#5d5c67,#403F4C)repeat-x;border-color:#403f4c;box-shadow:inset 0 1px rgba(255,255,255,.15),0 1px 1px rgba(0,0,0,.075)}.btn-dark:hover{color:#fff;background:#2e2e37 linear-gradient(180deg,#4e4d55,#2e2e37)repeat-x;border-color:#292830}.btn-dark:focus,.btn-dark.focus{color:#fff;background:#2e2e37 linear-gradient(180deg,#4e4d55,#2e2e37)repeat-x;border-color:#292830;box-shadow:inset 0 1px rgba(255,255,255,.15),0 1px 1px rgba(0,0,0,.075),0 0 0 .2rem rgba(93,92,103,.5)}.btn-dark.disabled,.btn-dark:disabled{color:#fff;background-color:#403f4c;border-color:#403f4c;background-image:none}.btn-dark:not(:disabled):not(.disabled):active,.btn-dark:not(:disabled):not(.disabled).active,.show>.btn-dark.dropdown-toggle{color:#fff;background-color:#292830;background-image:none;border-color:#232229}.btn-dark:not(:disabled):not(.disabled):active:focus,.btn-dark:not(:disabled):not(.disabled).active:focus,.show>.btn-dark.dropdown-toggle:focus{box-shadow:inset 0 3px 5px rgba(0,0,0,.125),0 0 0 .2rem rgba(93,92,103,.5)}.btn-outline-primary{color:#30638e;border-color:#30638e}.btn-outline-primary:hover{color:#fff;background-color:#30638e;border-color:#30638e}.btn-outline-primary:focus,.btn-outline-primary.focus{box-shadow:0 0 0 .2rem rgba(48,99,142,.5)}.btn-outline-primary.disabled,.btn-outline-primary:disabled{color:#30638e;background-color:transparent}.btn-outline-primary:not(:disabled):not(.disabled):active,.btn-outline-primary:not(:disabled):not(.disabled).active,.show>.btn-outline-primary.dropdown-toggle{color:#fff;background-color:#30638e;border-color:#30638e}.btn-outline-primary:not(:disabled):not(.disabled):active:focus,.btn-outline-primary:not(:disabled):not(.disabled).active:focus,.show>.btn-outline-primary.dropdown-toggle:focus{box-shadow:inset 0 3px 5px rgba(0,0,0,.125),0 0 0 .2rem rgba(48,99,142,.5)}.btn-outline-secondary{color:#ffa630;border-color:#ffa630}.btn-outline-secondary:hover{color:#fff;background-color:#ffa630;border-color:#ffa630}.btn-outline-secondary:focus,.btn-outline-secondary.focus{box-shadow:0 0 0 .2rem rgba(255,166,48,.5)}.btn-outline-secondary.disabled,.btn-outline-secondary:disabled{color:#ffa630;background-color:transparent}.btn-outline-secondary:not(:disabled):not(.disabled):active,.btn-outline-secondary:not(:disabled):not(.disabled).active,.show>.btn-outline-secondary.dropdown-toggle{color:#fff;background-color:#ffa630;border-color:#ffa630}.btn-outline-secondary:not(:disabled):not(.disabled):active:focus,.btn-outline-secondary:not(:disabled):not(.disabled).active:focus,.show>.btn-outline-secondary.dropdown-toggle:focus{box-shadow:inset 0 3px 5px rgba(0,0,0,.125),0 0 0 .2rem rgba(255,166,48,.5)}.btn-outline-success{color:#3772ff;border-color:#3772ff}.btn-outline-success:hover{color:#fff;background-color:#3772ff;border-color:#3772ff}.btn-outline-success:focus,.btn-outline-success.focus{box-shadow:0 0 0 .2rem rgba(55,114,255,.5)}.btn-outline-success.disabled,.btn-outline-success:disabled{color:#3772ff;background-color:transparent}.btn-outline-success:not(:disabled):not(.disabled):active,.btn-outline-success:not(:disabled):not(.disabled).active,.show>.btn-outline-success.dropdown-toggle{color:#fff;background-color:#3772ff;border-color:#3772ff}.btn-outline-success:not(:disabled):not(.disabled):active:focus,.btn-outline-success:not(:disabled):not(.disabled).active:focus,.show>.btn-outline-success.dropdown-toggle:focus{box-shadow:inset 0 3px 5px rgba(0,0,0,.125),0 0 0 .2rem rgba(55,114,255,.5)}.btn-outline-info{color:#c0e0de;border-color:#c0e0de}.btn-outline-info:hover{color:#222;background-color:#c0e0de;border-color:#c0e0de}.btn-outline-info:focus,.btn-outline-info.focus{box-shadow:0 0 0 .2rem rgba(192,224,222,.5)}.btn-outline-info.disabled,.btn-outline-info:disabled{color:#c0e0de;background-color:transparent}.btn-outline-info:not(:disabled):not(.disabled):active,.btn-outline-info:not(:disabled):not(.disabled).active,.show>.btn-outline-info.dropdown-toggle{color:#222;background-color:#c0e0de;border-color:#c0e0de}.btn-outline-info:not(:disabled):not(.disabled):active:focus,.btn-outline-info:not(:disabled):not(.disabled).active:focus,.show>.btn-outline-info.dropdown-toggle:focus{box-shadow:inset 0 3px 5px rgba(0,0,0,.125),0 0 0 .2rem rgba(192,224,222,.5)}.btn-outline-warning{color:#ed6a5a;border-color:#ed6a5a}.btn-outline-warning:hover{color:#fff;background-color:#ed6a5a;border-color:#ed6a5a}.btn-outline-warning:focus,.btn-outline-warning.focus{box-shadow:0 0 0 .2rem rgba(237,106,90,.5)}.btn-outline-warning.disabled,.btn-outline-warning:disabled{color:#ed6a5a;background-color:transparent}.btn-outline-warning:not(:disabled):not(.disabled):active,.btn-outline-warning:not(:disabled):not(.disabled).active,.show>.btn-outline-warning.dropdown-toggle{color:#fff;background-color:#ed6a5a;border-color:#ed6a5a}.btn-outline-warning:not(:disabled):not(.disabled):active:focus,.btn-outline-warning:not(:disabled):not(.disabled).active:focus,.show>.btn-outline-warning.dropdown-toggle:focus{box-shadow:inset 0 3px 5px rgba(0,0,0,.125),0 0 0 .2rem rgba(237,106,90,.5)}.btn-outline-danger{color:#ed6a5a;border-color:#ed6a5a}.btn-outline-danger:hover{color:#fff;background-color:#ed6a5a;border-color:#ed6a5a}.btn-outline-danger:focus,.btn-outline-danger.focus{box-shadow:0 0 0 .2rem rgba(237,106,90,.5)}.btn-outline-danger.disabled,.btn-outline-danger:disabled{color:#ed6a5a;background-color:transparent}.btn-outline-danger:not(:disabled):not(.disabled):active,.btn-outline-danger:not(:disabled):not(.disabled).active,.show>.btn-outline-danger.dropdown-toggle{color:#fff;background-color:#ed6a5a;border-color:#ed6a5a}.btn-outline-danger:not(:disabled):not(.disabled):active:focus,.btn-outline-danger:not(:disabled):not(.disabled).active:focus,.show>.btn-outline-danger.dropdown-toggle:focus{box-shadow:inset 0 3px 5px rgba(0,0,0,.125),0 0 0 .2rem rgba(237,106,90,.5)}.btn-outline-light{color:#d3f3ee;border-color:#d3f3ee}.btn-outline-light:hover{color:#222;background-color:#d3f3ee;border-color:#d3f3ee}.btn-outline-light:focus,.btn-outline-light.focus{box-shadow:0 0 0 .2rem rgba(211,243,238,.5)}.btn-outline-light.disabled,.btn-outline-light:disabled{color:#d3f3ee;background-color:transparent}.btn-outline-light:not(:disabled):not(.disabled):active,.btn-outline-light:not(:disabled):not(.disabled).active,.show>.btn-outline-light.dropdown-toggle{color:#222;background-color:#d3f3ee;border-color:#d3f3ee}.btn-outline-light:not(:disabled):not(.disabled):active:focus,.btn-outline-light:not(:disabled):not(.disabled).active:focus,.show>.btn-outline-light.dropdown-toggle:focus{box-shadow:inset 0 3px 5px rgba(0,0,0,.125),0 0 0 .2rem rgba(211,243,238,.5)}.btn-outline-dark{color:#403f4c;border-color:#403f4c}.btn-outline-dark:hover{color:#fff;background-color:#403f4c;border-color:#403f4c}.btn-outline-dark:focus,.btn-outline-dark.focus{box-shadow:0 0 0 .2rem rgba(64,63,76,.5)}.btn-outline-dark.disabled,.btn-outline-dark:disabled{color:#403f4c;background-color:transparent}.btn-outline-dark:not(:disabled):not(.disabled):active,.btn-outline-dark:not(:disabled):not(.disabled).active,.show>.btn-outline-dark.dropdown-toggle{color:#fff;background-color:#403f4c;border-color:#403f4c}.btn-outline-dark:not(:disabled):not(.disabled):active:focus,.btn-outline-dark:not(:disabled):not(.disabled).active:focus,.show>.btn-outline-dark.dropdown-toggle:focus{box-shadow:inset 0 3px 5px rgba(0,0,0,.125),0 0 0 .2rem rgba(64,63,76,.5)}.btn-link{font-weight:400;color:#3176d9;text-decoration:none}.btn-link:hover{color:#1e53a0;text-decoration:none}.btn-link:focus,.btn-link.focus{text-decoration:none}.btn-link:disabled,.btn-link.disabled{color:#797676;pointer-events:none}.btn-lg,.btn-group-lg>.btn{padding:.5rem 1rem;font-size:1.25rem;line-height:1.5;border-radius:.3rem}.btn-sm,.btn-group-sm>.btn{padding:.25rem .5rem;font-size:.875rem;line-height:1.5;border-radius:.2rem}.btn-block{display:block;width:100%}.btn-block+.btn-block{margin-top:.5rem}input[type=submit].btn-block,input[type=reset].btn-block,input[type=button].btn-block{width:100%}.fade{transition:opacity .15s linear}@media(prefers-reduced-motion:reduce){.fade{transition:none}}.fade:not(.show){opacity:0}.collapse:not(.show){display:none}.collapsing{position:relative;height:0;overflow:hidden;transition:height .35s ease}@media(prefers-reduced-motion:reduce){.collapsing{transition:none}}.dropup,.dropright,.dropdown,.dropleft{position:relative}.dropdown-toggle{white-space:nowrap}.dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:.3em solid;border-right:.3em solid transparent;border-bottom:0;border-left:.3em solid transparent}.dropdown-toggle:empty::after{margin-left:0}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:10rem;padding:.5rem 0;margin:.125rem 0 0;font-size:1rem;color:#222;text-align:left;list-style:none;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,.15);border-radius:.25rem;box-shadow:0 .5rem 1rem rgba(0,0,0,.175)}.dropdown-menu-left{right:auto;left:0}.dropdown-menu-right{right:0;left:auto}@media(min-width:576px){.dropdown-menu-sm-left{right:auto;left:0}.dropdown-menu-sm-right{right:0;left:auto}}@media(min-width:768px){.dropdown-menu-md-left{right:auto;left:0}.dropdown-menu-md-right{right:0;left:auto}}@media(min-width:992px){.dropdown-menu-lg-left{right:auto;left:0}.dropdown-menu-lg-right{right:0;left:auto}}@media(min-width:1200px){.dropdown-menu-xl-left{right:auto;left:0}.dropdown-menu-xl-right{right:0;left:auto}}.dropup .dropdown-menu{top:auto;bottom:100%;margin-top:0;margin-bottom:.125rem}.dropup .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:0;border-right:.3em solid transparent;border-bottom:.3em solid;border-left:.3em solid transparent}.dropup .dropdown-toggle:empty::after{margin-left:0}.dropright .dropdown-menu{top:0;right:auto;left:100%;margin-top:0;margin-left:.125rem}.dropright .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:.3em solid transparent;border-right:0;border-bottom:.3em solid transparent;border-left:.3em solid}.dropright .dropdown-toggle:empty::after{margin-left:0}.dropright .dropdown-toggle::after{vertical-align:0}.dropleft .dropdown-menu{top:0;right:100%;left:auto;margin-top:0;margin-right:.125rem}.dropleft .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:""}.dropleft .dropdown-toggle::after{display:none}.dropleft .dropdown-toggle::before{display:inline-block;margin-right:.255em;vertical-align:.255em;content:"";border-top:.3em solid transparent;border-right:.3em solid;border-bottom:.3em solid transparent}.dropleft .dropdown-toggle:empty::after{margin-left:0}.dropleft .dropdown-toggle::before{vertical-align:0}.dropdown-menu[x-placement^=top],.dropdown-menu[x-placement^=right],.dropdown-menu[x-placement^=bottom],.dropdown-menu[x-placement^=left]{right:auto;bottom:auto}.dropdown-divider{height:0;margin:.5rem 0;overflow:hidden;border-top:1px solid #eee}.dropdown-item{display:block;width:100%;padding:.25rem 1.5rem;clear:both;font-weight:400;color:#222;text-align:inherit;white-space:nowrap;background-color:transparent;border:0}.dropdown-item:hover,.dropdown-item:focus{color:#151515;text-decoration:none;background:#eee linear-gradient(180deg,#f1f1f1,#eee)repeat-x}.dropdown-item.active,.dropdown-item:active{color:#fff;text-decoration:none;background:#30638e linear-gradient(180deg,#4f7a9f,#30638E)repeat-x}.dropdown-item.disabled,.dropdown-item:disabled{color:#adb5bd;pointer-events:none;background-color:transparent;background-image:none}.dropdown-menu.show{display:block}.dropdown-header{display:block;padding:.5rem 1.5rem;margin-bottom:0;font-size:.875rem;color:#797676;white-space:nowrap}.dropdown-item-text{display:block;padding:.25rem 1.5rem;color:#222}.btn-group,.btn-group-vertical{position:relative;display:inline-flex;vertical-align:middle}.btn-group>.btn,.btn-group-vertical>.btn{position:relative;flex:auto}.btn-group>.btn:hover,.btn-group-vertical>.btn:hover{z-index:1}.btn-group>.btn:focus,.btn-group>.btn:active,.btn-group>.btn.active,.btn-group-vertical>.btn:focus,.btn-group-vertical>.btn:active,.btn-group-vertical>.btn.active{z-index:1}.btn-toolbar{display:flex;flex-wrap:wrap;justify-content:flex-start}.btn-toolbar .input-group{width:auto}.btn-group>.btn:not(:first-child),.btn-group>.btn-group:not(:first-child){margin-left:-1px}.btn-group>.btn:not(:last-child):not(.dropdown-toggle),.btn-group>.btn-group:not(:last-child)>.btn{border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn:not(:first-child),.btn-group>.btn-group:not(:first-child)>.btn{border-top-left-radius:0;border-bottom-left-radius:0}.dropdown-toggle-split{padding-right:.5625rem;padding-left:.5625rem}.dropdown-toggle-split::after,.dropup .dropdown-toggle-split::after,.dropright .dropdown-toggle-split::after{margin-left:0}.dropleft .dropdown-toggle-split::before{margin-right:0}.btn-sm+.dropdown-toggle-split,.btn-group-sm>.btn+.dropdown-toggle-split{padding-right:.375rem;padding-left:.375rem}.btn-lg+.dropdown-toggle-split,.btn-group-lg>.btn+.dropdown-toggle-split{padding-right:.75rem;padding-left:.75rem}.btn-group.show .dropdown-toggle{box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn-group.show .dropdown-toggle.btn-link{box-shadow:none}.btn-group-vertical{flex-direction:column;align-items:flex-start;justify-content:center}.btn-group-vertical>.btn,.btn-group-vertical>.btn-group{width:100%}.btn-group-vertical>.btn:not(:first-child),.btn-group-vertical>.btn-group:not(:first-child){margin-top:-1px}.btn-group-vertical>.btn:not(:last-child):not(.dropdown-toggle),.btn-group-vertical>.btn-group:not(:last-child)>.btn{border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn:not(:first-child),.btn-group-vertical>.btn-group:not(:first-child)>.btn{border-top-left-radius:0;border-top-right-radius:0}.btn-group-toggle>.btn,.btn-group-toggle>.btn-group>.btn{margin-bottom:0}.btn-group-toggle>.btn input[type=radio],.btn-group-toggle>.btn input[type=checkbox],.btn-group-toggle>.btn-group>.btn input[type=radio],.btn-group-toggle>.btn-group>.btn input[type=checkbox]{position:absolute;clip:rect(0,0,0,0);pointer-events:none}.input-group{position:relative;display:flex;flex-wrap:wrap;align-items:stretch;width:100%}.input-group>.form-control,.input-group>.form-control-plaintext,.input-group>.custom-select,.input-group>.custom-file{position:relative;flex:auto;width:1%;min-width:0;margin-bottom:0}.input-group>.form-control+.form-control,.input-group>.form-control+.custom-select,.input-group>.form-control+.custom-file,.input-group>.form-control-plaintext+.form-control,.input-group>.form-control-plaintext+.custom-select,.input-group>.form-control-plaintext+.custom-file,.input-group>.custom-select+.form-control,.input-group>.custom-select+.custom-select,.input-group>.custom-select+.custom-file,.input-group>.custom-file+.form-control,.input-group>.custom-file+.custom-select,.input-group>.custom-file+.custom-file{margin-left:-1px}.input-group>.form-control:focus,.input-group>.custom-select:focus,.input-group>.custom-file .custom-file-input:focus~.custom-file-label{z-index:3}.input-group>.custom-file .custom-file-input:focus{z-index:4}.input-group>.form-control:not(:first-child),.input-group>.custom-select:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.input-group>.custom-file{display:flex;align-items:center}.input-group>.custom-file:not(:last-child) .custom-file-label,.input-group>.custom-file:not(:last-child) .custom-file-label::after{border-top-right-radius:0;border-bottom-right-radius:0}.input-group>.custom-file:not(:first-child) .custom-file-label{border-top-left-radius:0;border-bottom-left-radius:0}.input-group:not(.has-validation)>.form-control:not(:last-child),.input-group:not(.has-validation)>.custom-select:not(:last-child),.input-group:not(.has-validation)>.custom-file:not(:last-child) .custom-file-label,.input-group:not(.has-validation)>.custom-file:not(:last-child) .custom-file-label::after{border-top-right-radius:0;border-bottom-right-radius:0}.input-group.has-validation>.form-control:nth-last-child(n+3),.input-group.has-validation>.custom-select:nth-last-child(n+3),.input-group.has-validation>.custom-file:nth-last-child(n+3) .custom-file-label,.input-group.has-validation>.custom-file:nth-last-child(n+3) .custom-file-label::after{border-top-right-radius:0;border-bottom-right-radius:0}.input-group-prepend,.input-group-append{display:flex}.input-group-prepend .btn,.input-group-append .btn{position:relative;z-index:2}.input-group-prepend .btn:focus,.input-group-append .btn:focus{z-index:3}.input-group-prepend .btn+.btn,.input-group-prepend .btn+.input-group-text,.input-group-prepend .input-group-text+.input-group-text,.input-group-prepend .input-group-text+.btn,.input-group-append .btn+.btn,.input-group-append .btn+.input-group-text,.input-group-append .input-group-text+.input-group-text,.input-group-append .input-group-text+.btn{margin-left:-1px}.input-group-prepend{margin-right:-1px}.input-group-append{margin-left:-1px}.input-group-text{display:flex;align-items:center;padding:.375rem .75rem;margin-bottom:0;font-size:1rem;font-weight:400;line-height:1.5;color:#495057;text-align:center;white-space:nowrap;background-color:#eee;border:1px solid #ccc;border-radius:.25rem}.input-group-text input[type=radio],.input-group-text input[type=checkbox]{margin-top:0}.input-group-lg>.form-control:not(textarea),.input-group-lg>.custom-select{height:calc(1.5em + 1rem + 2px)}.input-group-lg>.form-control,.input-group-lg>.custom-select,.input-group-lg>.input-group-prepend>.input-group-text,.input-group-lg>.input-group-append>.input-group-text,.input-group-lg>.input-group-prepend>.btn,.input-group-lg>.input-group-append>.btn{padding:.5rem 1rem;font-size:1.25rem;line-height:1.5;border-radius:.3rem}.input-group-sm>.form-control:not(textarea),.input-group-sm>.custom-select{height:calc(1.5em + .5rem + 2px)}.input-group-sm>.form-control,.input-group-sm>.custom-select,.input-group-sm>.input-group-prepend>.input-group-text,.input-group-sm>.input-group-append>.input-group-text,.input-group-sm>.input-group-prepend>.btn,.input-group-sm>.input-group-append>.btn{padding:.25rem .5rem;font-size:.875rem;line-height:1.5;border-radius:.2rem}.input-group-lg>.custom-select,.input-group-sm>.custom-select{padding-right:1.75rem}.input-group>.input-group-prepend>.btn,.input-group>.input-group-prepend>.input-group-text,.input-group:not(.has-validation)>.input-group-append:not(:last-child)>.btn,.input-group:not(.has-validation)>.input-group-append:not(:last-child)>.input-group-text,.input-group.has-validation>.input-group-append:nth-last-child(n+3)>.btn,.input-group.has-validation>.input-group-append:nth-last-child(n+3)>.input-group-text,.input-group>.input-group-append:last-child>.btn:not(:last-child):not(.dropdown-toggle),.input-group>.input-group-append:last-child>.input-group-text:not(:last-child){border-top-right-radius:0;border-bottom-right-radius:0}.input-group>.input-group-append>.btn,.input-group>.input-group-append>.input-group-text,.input-group>.input-group-prepend:not(:first-child)>.btn,.input-group>.input-group-prepend:not(:first-child)>.input-group-text,.input-group>.input-group-prepend:first-child>.btn:not(:first-child),.input-group>.input-group-prepend:first-child>.input-group-text:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.custom-control{position:relative;z-index:1;display:block;min-height:1.5rem;padding-left:1.5rem;-webkit-print-color-adjust:exact;color-adjust:exact}.custom-control-inline{display:inline-flex;margin-right:1rem}.custom-control-input{position:absolute;left:0;z-index:-1;width:1rem;height:1.25rem;opacity:0}.custom-control-input:checked~.custom-control-label::before{color:#fff;border-color:#30638e;background:#30638e linear-gradient(180deg,#4f7a9f,#30638E)repeat-x;box-shadow:}.custom-control-input:focus~.custom-control-label::before{box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 0 .2rem rgba(48,99,142,.25)}.custom-control-input:focus:not(:checked)~.custom-control-label::before{border-color:#6fa3ce}.custom-control-input:not(:disabled):active~.custom-control-label::before{color:#fff;background-color:#95bbdb;border-color:#95bbdb;box-shadow:}.custom-control-input[disabled]~.custom-control-label,.custom-control-input:disabled~.custom-control-label{color:#797676}.custom-control-input[disabled]~.custom-control-label::before,.custom-control-input:disabled~.custom-control-label::before{background-color:#eee}.custom-control-label{position:relative;margin-bottom:0;vertical-align:top}.custom-control-label::before{position:absolute;top:.25rem;left:-1.5rem;display:block;width:1rem;height:1rem;pointer-events:none;content:"";background-color:#fff;border:#adb5bd solid 1px;box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.custom-control-label::after{position:absolute;top:.25rem;left:-1.5rem;display:block;width:1rem;height:1rem;content:"";background:50%/50% no-repeat}.custom-checkbox .custom-control-label::before{border-radius:.25rem}.custom-checkbox .custom-control-input:checked~.custom-control-label::after{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='8' height='8' viewBox='0 0 8 8'%3e%3cpath fill='%23fff' d='M6.564.75l-3.59 3.612-1.538-1.55L0 4.26l2.974 2.99L8 2.193z'/%3e%3c/svg%3e")}.custom-checkbox .custom-control-input:indeterminate~.custom-control-label::before{border-color:#30638e;background:#30638e linear-gradient(180deg,#4f7a9f,#30638E)repeat-x;box-shadow:}.custom-checkbox .custom-control-input:indeterminate~.custom-control-label::after{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='4' height='4' viewBox='0 0 4 4'%3e%3cpath stroke='%23fff' d='M0 2h4'/%3e%3c/svg%3e")}.custom-checkbox .custom-control-input:disabled:checked~.custom-control-label::before{background:rgba(48,99,142,.5)linear-gradient(180deg,rgba(120,153,181,.575),rgba(48,99,142,.5))repeat-x}.custom-checkbox .custom-control-input:disabled:indeterminate~.custom-control-label::before{background:rgba(48,99,142,.5)linear-gradient(180deg,rgba(120,153,181,.575),rgba(48,99,142,.5))repeat-x}.custom-radio .custom-control-label::before{border-radius:50%}.custom-radio .custom-control-input:checked~.custom-control-label::after{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%23fff'/%3e%3c/svg%3e")}.custom-radio .custom-control-input:disabled:checked~.custom-control-label::before{background:rgba(48,99,142,.5)linear-gradient(180deg,rgba(120,153,181,.575),rgba(48,99,142,.5))repeat-x}.custom-switch{padding-left:2.25rem}.custom-switch .custom-control-label::before{left:-2.25rem;width:1.75rem;pointer-events:all;border-radius:.5rem}.custom-switch .custom-control-label::after{top:calc(.25rem + 2px);left:calc(-2.25rem + 2px);width:calc(1rem - 4px);height:calc(1rem - 4px);background-color:#adb5bd;border-radius:.5rem;transition:transform .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media(prefers-reduced-motion:reduce){.custom-switch .custom-control-label::after{transition:none}}.custom-switch .custom-control-input:checked~.custom-control-label::after{background-color:#fff;transform:translateX(.75rem)}.custom-switch .custom-control-input:disabled:checked~.custom-control-label::before{background:rgba(48,99,142,.5)linear-gradient(180deg,rgba(120,153,181,.575),rgba(48,99,142,.5))repeat-x}.custom-select{display:inline-block;width:100%;height:calc(1.5em + .75rem + 2px);padding:.375rem 1.75rem .375rem .75rem;font-size:1rem;font-weight:400;line-height:1.5;color:#495057;vertical-align:middle;background:#fff url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='4' height='5' viewBox='0 0 4 5'%3e%3cpath fill='%23333' d='M2 0L0 2h4zm0 5L0 3h4z'/%3e%3c/svg%3e")right .75rem center/8px 10px no-repeat;border:1px solid #ccc;border-radius:.25rem;box-shadow:inset 0 1px 2px rgba(0,0,0,.075);-webkit-appearance:none;-moz-appearance:none;appearance:none}.custom-select:focus{border-color:#6fa3ce;outline:0;box-shadow:inset 0 1px 2px rgba(0,0,0,.075),0 0 0 .2rem rgba(48,99,142,.25)}.custom-select:focus::-ms-value{color:#495057;background-color:#fff}.custom-select[multiple],.custom-select[size]:not([size="1"]){height:auto;padding-right:.75rem;background-image:none}.custom-select:disabled{color:#797676;background-color:#eee}.custom-select::-ms-expand{display:none}.custom-select:-moz-focusring{color:transparent;text-shadow:0 0 0 #495057}.custom-select-sm{height:calc(1.5em + .5rem + 2px);padding-top:.25rem;padding-bottom:.25rem;padding-left:.5rem;font-size:.875rem}.custom-select-lg{height:calc(1.5em + 1rem + 2px);padding-top:.5rem;padding-bottom:.5rem;padding-left:1rem;font-size:1.25rem}.custom-file{position:relative;display:inline-block;width:100%;height:calc(1.5em + .75rem + 2px);margin-bottom:0}.custom-file-input{position:relative;z-index:2;width:100%;height:calc(1.5em + .75rem + 2px);margin:0;overflow:hidden;opacity:0}.custom-file-input:focus~.custom-file-label{border-color:#6fa3ce;box-shadow:0 0 0 .2rem rgba(48,99,142,.25)}.custom-file-input[disabled]~.custom-file-label,.custom-file-input:disabled~.custom-file-label{background-color:#eee}.custom-file-input:lang(en)~.custom-file-label::after{content:"Browse"}.custom-file-input~.custom-file-label[data-browse]::after{content:attr(data-browse)}.custom-file-label{position:absolute;top:0;right:0;left:0;z-index:1;height:calc(1.5em + .75rem + 2px);padding:.375rem .75rem;overflow:hidden;font-weight:400;line-height:1.5;color:#495057;background-color:#fff;border:1px solid #ccc;border-radius:.25rem;box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.custom-file-label::after{position:absolute;top:0;right:0;bottom:0;z-index:3;display:block;height:calc(1.5em + .75rem);padding:.375rem .75rem;line-height:1.5;color:#495057;content:"Browse";background:#eee linear-gradient(180deg,#f1f1f1,#eee)repeat-x;border-left:inherit;border-radius:0 .25rem .25rem 0}.custom-range{width:100%;height:1.4rem;padding:0;background-color:transparent;-webkit-appearance:none;-moz-appearance:none;appearance:none}.custom-range:focus{outline:0}.custom-range:focus::-webkit-slider-thumb{box-shadow:0 0 0 1px #fff,0 0 0 .2rem rgba(48,99,142,.25)}.custom-range:focus::-moz-range-thumb{box-shadow:0 0 0 1px #fff,0 0 0 .2rem rgba(48,99,142,.25)}.custom-range:focus::-ms-thumb{box-shadow:0 0 0 1px #fff,0 0 0 .2rem rgba(48,99,142,.25)}.custom-range::-moz-focus-outer{border:0}.custom-range::-webkit-slider-thumb{width:1rem;height:1rem;margin-top:-.25rem;background:#30638e linear-gradient(180deg,#4f7a9f,#30638E)repeat-x;border:0;border-radius:1rem;box-shadow:0 .1rem .25rem rgba(0,0,0,.1);-webkit-transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;-webkit-appearance:none;appearance:none}@media(prefers-reduced-motion:reduce){.custom-range::-webkit-slider-thumb{-webkit-transition:none;transition:none}}.custom-range::-webkit-slider-thumb:active{background:#95bbdb linear-gradient(180deg,#a5c5e1,#95bbdb)repeat-x}.custom-range::-webkit-slider-runnable-track{width:100%;height:.5rem;color:transparent;cursor:pointer;background-color:#dee2e6;border-color:transparent;border-radius:1rem;box-shadow:inset 0 .25rem .25rem rgba(0,0,0,.1)}.custom-range::-moz-range-thumb{width:1rem;height:1rem;background:#30638e linear-gradient(180deg,#4f7a9f,#30638E)repeat-x;border:0;border-radius:1rem;box-shadow:0 .1rem .25rem rgba(0,0,0,.1);-moz-transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;-moz-appearance:none;appearance:none}@media(prefers-reduced-motion:reduce){.custom-range::-moz-range-thumb{-moz-transition:none;transition:none}}.custom-range::-moz-range-thumb:active{background:#95bbdb linear-gradient(180deg,#a5c5e1,#95bbdb)repeat-x}.custom-range::-moz-range-track{width:100%;height:.5rem;color:transparent;cursor:pointer;background-color:#dee2e6;border-color:transparent;border-radius:1rem;box-shadow:inset 0 .25rem .25rem rgba(0,0,0,.1)}.custom-range::-ms-thumb{width:1rem;height:1rem;margin-top:0;margin-right:.2rem;margin-left:.2rem;background:#30638e linear-gradient(180deg,#4f7a9f,#30638E)repeat-x;border:0;border-radius:1rem;box-shadow:0 .1rem .25rem rgba(0,0,0,.1);-ms-transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;appearance:none}@media(prefers-reduced-motion:reduce){.custom-range::-ms-thumb{-ms-transition:none;transition:none}}.custom-range::-ms-thumb:active{background:#95bbdb linear-gradient(180deg,#a5c5e1,#95bbdb)repeat-x}.custom-range::-ms-track{width:100%;height:.5rem;color:transparent;cursor:pointer;background-color:transparent;border-color:transparent;border-width:.5rem;box-shadow:inset 0 .25rem .25rem rgba(0,0,0,.1)}.custom-range::-ms-fill-lower{background-color:#dee2e6;border-radius:1rem}.custom-range::-ms-fill-upper{margin-right:15px;background-color:#dee2e6;border-radius:1rem}.custom-range:disabled::-webkit-slider-thumb{background-color:#adb5bd}.custom-range:disabled::-webkit-slider-runnable-track{cursor:default}.custom-range:disabled::-moz-range-thumb{background-color:#adb5bd}.custom-range:disabled::-moz-range-track{cursor:default}.custom-range:disabled::-ms-thumb{background-color:#adb5bd}.custom-control-label::before,.custom-file-label,.custom-select{transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media(prefers-reduced-motion:reduce){.custom-control-label::before,.custom-file-label,.custom-select{transition:none}}.nav{display:flex;flex-wrap:wrap;padding-left:0;margin-bottom:0;list-style:none}.nav-link{display:block;padding:.5rem 1rem}.nav-link:hover,.nav-link:focus{text-decoration:none}.nav-link.disabled{color:#797676;pointer-events:none;cursor:default}.nav-tabs{border-bottom:1px solid #dee2e6}.nav-tabs .nav-link{margin-bottom:-1px;border:1px solid transparent;border-top-left-radius:.25rem;border-top-right-radius:.25rem}.nav-tabs .nav-link:hover,.nav-tabs .nav-link:focus{border-color:#eee #eee #dee2e6}.nav-tabs .nav-link.disabled{color:#797676;background-color:transparent;border-color:transparent}.nav-tabs .nav-link.active,.nav-tabs .nav-item.show .nav-link{color:#495057;background-color:#fff;border-color:#dee2e6 #dee2e6 #fff}.nav-tabs .dropdown-menu{margin-top:-1px;border-top-left-radius:0;border-top-right-radius:0}.nav-pills .nav-link{border-radius:.25rem}.nav-pills .nav-link.active,.nav-pills .show>.nav-link{color:#fff;background-color:#30638e}.nav-fill>.nav-link,.nav-fill .nav-item{flex:auto;text-align:center}.nav-justified>.nav-link,.nav-justified .nav-item{flex-basis:0;flex-grow:1;text-align:center}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.navbar{position:relative;display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;padding:.5rem 1rem}.navbar .container,.navbar .container-fluid,.navbar .container-sm,.navbar .container-md,.navbar .container-lg,.navbar .container-xl{display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between}.navbar-brand{display:inline-block;padding-top:.3125rem;padding-bottom:.3125rem;margin-right:1rem;font-size:1.25rem;line-height:inherit;white-space:nowrap}.navbar-brand:hover,.navbar-brand:focus{text-decoration:none}.navbar-nav{display:flex;flex-direction:column;padding-left:0;margin-bottom:0;list-style:none}.navbar-nav .nav-link{padding-right:0;padding-left:0}.navbar-nav .dropdown-menu{position:static;float:none}.navbar-text{display:inline-block;padding-top:.5rem;padding-bottom:.5rem}.navbar-collapse{flex-basis:100%;flex-grow:1;align-items:center}.navbar-toggler{padding:.25rem .75rem;font-size:1.25rem;line-height:1;background-color:transparent;border:1px solid transparent;border-radius:.25rem}.navbar-toggler:hover,.navbar-toggler:focus{text-decoration:none}.navbar-toggler-icon{display:inline-block;width:1.5em;height:1.5em;vertical-align:middle;content:"";background:50%/100% 100% no-repeat}.navbar-nav-scroll{max-height:75vh;overflow-y:auto}@media(max-width:575.98px){.navbar-expand-sm>.container,.navbar-expand-sm>.container-fluid,.navbar-expand-sm>.container-sm,.navbar-expand-sm>.container-md,.navbar-expand-sm>.container-lg,.navbar-expand-sm>.container-xl{padding-right:0;padding-left:0}}@media(min-width:576px){.navbar-expand-sm{flex-flow:row nowrap;justify-content:flex-start}.navbar-expand-sm .navbar-nav{flex-direction:row}.navbar-expand-sm .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-sm .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-sm>.container,.navbar-expand-sm>.container-fluid,.navbar-expand-sm>.container-sm,.navbar-expand-sm>.container-md,.navbar-expand-sm>.container-lg,.navbar-expand-sm>.container-xl{flex-wrap:nowrap}.navbar-expand-sm .navbar-nav-scroll{overflow:visible}.navbar-expand-sm .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-sm .navbar-toggler{display:none}}@media(max-width:767.98px){.navbar-expand-md>.container,.navbar-expand-md>.container-fluid,.navbar-expand-md>.container-sm,.navbar-expand-md>.container-md,.navbar-expand-md>.container-lg,.navbar-expand-md>.container-xl{padding-right:0;padding-left:0}}@media(min-width:768px){.navbar-expand-md{flex-flow:row nowrap;justify-content:flex-start}.navbar-expand-md .navbar-nav{flex-direction:row}.navbar-expand-md .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-md .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-md>.container,.navbar-expand-md>.container-fluid,.navbar-expand-md>.container-sm,.navbar-expand-md>.container-md,.navbar-expand-md>.container-lg,.navbar-expand-md>.container-xl{flex-wrap:nowrap}.navbar-expand-md .navbar-nav-scroll{overflow:visible}.navbar-expand-md .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-md .navbar-toggler{display:none}}@media(max-width:991.98px){.navbar-expand-lg>.container,.navbar-expand-lg>.container-fluid,.navbar-expand-lg>.container-sm,.navbar-expand-lg>.container-md,.navbar-expand-lg>.container-lg,.navbar-expand-lg>.container-xl{padding-right:0;padding-left:0}}@media(min-width:992px){.navbar-expand-lg{flex-flow:row nowrap;justify-content:flex-start}.navbar-expand-lg .navbar-nav{flex-direction:row}.navbar-expand-lg .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-lg .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-lg>.container,.navbar-expand-lg>.container-fluid,.navbar-expand-lg>.container-sm,.navbar-expand-lg>.container-md,.navbar-expand-lg>.container-lg,.navbar-expand-lg>.container-xl{flex-wrap:nowrap}.navbar-expand-lg .navbar-nav-scroll{overflow:visible}.navbar-expand-lg .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-lg .navbar-toggler{display:none}}@media(max-width:1199.98px){.navbar-expand-xl>.container,.navbar-expand-xl>.container-fluid,.navbar-expand-xl>.container-sm,.navbar-expand-xl>.container-md,.navbar-expand-xl>.container-lg,.navbar-expand-xl>.container-xl{padding-right:0;padding-left:0}}@media(min-width:1200px){.navbar-expand-xl{flex-flow:row nowrap;justify-content:flex-start}.navbar-expand-xl .navbar-nav{flex-direction:row}.navbar-expand-xl .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-xl .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-xl>.container,.navbar-expand-xl>.container-fluid,.navbar-expand-xl>.container-sm,.navbar-expand-xl>.container-md,.navbar-expand-xl>.container-lg,.navbar-expand-xl>.container-xl{flex-wrap:nowrap}.navbar-expand-xl .navbar-nav-scroll{overflow:visible}.navbar-expand-xl .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-xl .navbar-toggler{display:none}}.navbar-expand{flex-flow:row nowrap;justify-content:flex-start}.navbar-expand>.container,.navbar-expand>.container-fluid,.navbar-expand>.container-sm,.navbar-expand>.container-md,.navbar-expand>.container-lg,.navbar-expand>.container-xl{padding-right:0;padding-left:0}.navbar-expand .navbar-nav{flex-direction:row}.navbar-expand .navbar-nav .dropdown-menu{position:absolute}.navbar-expand .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand>.container,.navbar-expand>.container-fluid,.navbar-expand>.container-sm,.navbar-expand>.container-md,.navbar-expand>.container-lg,.navbar-expand>.container-xl{flex-wrap:nowrap}.navbar-expand .navbar-nav-scroll{overflow:visible}.navbar-expand .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand .navbar-toggler{display:none}.navbar-light .navbar-brand{color:rgba(0,0,0,.9)}.navbar-light .navbar-brand:hover,.navbar-light .navbar-brand:focus{color:rgba(0,0,0,.9)}.navbar-light .navbar-nav .nav-link{color:rgba(0,0,0,.5)}.navbar-light .navbar-nav .nav-link:hover,.navbar-light .navbar-nav .nav-link:focus{color:rgba(0,0,0,.7)}.navbar-light .navbar-nav .nav-link.disabled{color:rgba(0,0,0,.3)}.navbar-light .navbar-nav .show>.nav-link,.navbar-light .navbar-nav .active>.nav-link,.navbar-light .navbar-nav .nav-link.show,.navbar-light .navbar-nav .nav-link.active{color:rgba(0,0,0,.9)}.navbar-light .navbar-toggler{color:rgba(0,0,0,.5);border-color:rgba(0,0,0,.1)}.navbar-light .navbar-toggler-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='30' height='30' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%280, 0, 0, 0.5%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e")}.navbar-light .navbar-text{color:rgba(0,0,0,.5)}.navbar-light .navbar-text a{color:rgba(0,0,0,.9)}.navbar-light .navbar-text a:hover,.navbar-light .navbar-text a:focus{color:rgba(0,0,0,.9)}.navbar-dark .navbar-brand{color:#fff}.navbar-dark .navbar-brand:hover,.navbar-dark .navbar-brand:focus{color:#fff}.navbar-dark .navbar-nav .nav-link{color:rgba(255,255,255,.75)}.navbar-dark .navbar-nav .nav-link:hover,.navbar-dark .navbar-nav .nav-link:focus{color:rgba(255,255,255,.5)}.navbar-dark .navbar-nav .nav-link.disabled{color:rgba(255,255,255,.25)}.navbar-dark .navbar-nav .show>.nav-link,.navbar-dark .navbar-nav .active>.nav-link,.navbar-dark .navbar-nav .nav-link.show,.navbar-dark .navbar-nav .nav-link.active{color:#fff}.navbar-dark .navbar-toggler{color:rgba(255,255,255,.75);border-color:rgba(255,255,255,.1)}.navbar-dark .navbar-toggler-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='30' height='30' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%28255, 255, 255, 0.75%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e")}.navbar-dark .navbar-text{color:rgba(255,255,255,.75)}.navbar-dark .navbar-text a{color:#fff}.navbar-dark .navbar-text a:hover,.navbar-dark .navbar-text a:focus{color:#fff}.card,.td-content .highlight{position:relative;display:flex;flex-direction:column;min-width:0;word-wrap:break-word;background-color:#fff;background-clip:border-box;border:1px solid rgba(0,0,0,.125);border-radius:.25rem}.card>hr,.td-content .highlight>hr{margin-right:0;margin-left:0}.card>.list-group,.td-content .highlight>.list-group{border-top:inherit;border-bottom:inherit}.card>.list-group:first-child,.td-content .highlight>.list-group:first-child{border-top-width:0;border-top-left-radius:calc(.25rem - 1px);border-top-right-radius:calc(.25rem - 1px)}.card>.list-group:last-child,.td-content .highlight>.list-group:last-child{border-bottom-width:0;border-bottom-right-radius:calc(.25rem - 1px);border-bottom-left-radius:calc(.25rem - 1px)}.card>.card-header+.list-group,.td-content .highlight>.card-header+.list-group,.card>.list-group+.card-footer,.td-content .highlight>.list-group+.card-footer{border-top:0}.card-body{flex:auto;min-height:1px;padding:1.25rem}.card-title{margin-bottom:.75rem}.card-subtitle{margin-top:-.375rem;margin-bottom:0}.card-text:last-child{margin-bottom:0}.card-link:hover{text-decoration:none}.card-link+.card-link{margin-left:1.25rem}.card-header{padding:.75rem 1.25rem;margin-bottom:0;background-color:rgba(0,0,0,3%);border-bottom:1px solid rgba(0,0,0,.125)}.card-header:first-child{border-radius:calc(.25rem - 1px)calc(.25rem - 1px)0 0}.card-footer{padding:.75rem 1.25rem;background-color:rgba(0,0,0,3%);border-top:1px solid rgba(0,0,0,.125)}.card-footer:last-child{border-radius:0 0 calc(.25rem - 1px)calc(.25rem - 1px)}.card-header-tabs{margin-right:-.625rem;margin-bottom:-.75rem;margin-left:-.625rem;border-bottom:0}.card-header-pills{margin-right:-.625rem;margin-left:-.625rem}.card-img-overlay{position:absolute;top:0;right:0;bottom:0;left:0;padding:1.25rem;border-radius:calc(.25rem - 1px)}.card-img,.card-img-top,.card-img-bottom{flex-shrink:0;width:100%}.card-img,.card-img-top{border-top-left-radius:calc(.25rem - 1px);border-top-right-radius:calc(.25rem - 1px)}.card-img,.card-img-bottom{border-bottom-right-radius:calc(.25rem - 1px);border-bottom-left-radius:calc(.25rem - 1px)}.card-deck .card,.card-deck .td-content .highlight,.td-content .card-deck .highlight{margin-bottom:15px}@media(min-width:576px){.card-deck{display:flex;flex-flow:row wrap;margin-right:-15px;margin-left:-15px}.card-deck .card,.card-deck .td-content .highlight,.td-content .card-deck .highlight{flex:1 0;margin-right:15px;margin-bottom:0;margin-left:15px}}.card-group>.card,.td-content .card-group>.highlight{margin-bottom:15px}@media(min-width:576px){.card-group{display:flex;flex-flow:row wrap}.card-group>.card,.td-content .card-group>.highlight{flex:1 0;margin-bottom:0}.card-group>.card+.card,.td-content .card-group>.highlight+.card,.td-content .card-group>.card+.highlight,.td-content .card-group>.highlight+.highlight{margin-left:0;border-left:0}.card-group>.card:not(:last-child),.td-content .card-group>.highlight:not(:last-child){border-top-right-radius:0;border-bottom-right-radius:0}.card-group>.card:not(:last-child) .card-img-top,.td-content .card-group>.highlight:not(:last-child) .card-img-top,.card-group>.card:not(:last-child) .card-header,.td-content .card-group>.highlight:not(:last-child) .card-header{border-top-right-radius:0}.card-group>.card:not(:last-child) .card-img-bottom,.td-content .card-group>.highlight:not(:last-child) .card-img-bottom,.card-group>.card:not(:last-child) .card-footer,.td-content .card-group>.highlight:not(:last-child) .card-footer{border-bottom-right-radius:0}.card-group>.card:not(:first-child),.td-content .card-group>.highlight:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.card-group>.card:not(:first-child) .card-img-top,.td-content .card-group>.highlight:not(:first-child) .card-img-top,.card-group>.card:not(:first-child) .card-header,.td-content .card-group>.highlight:not(:first-child) .card-header{border-top-left-radius:0}.card-group>.card:not(:first-child) .card-img-bottom,.td-content .card-group>.highlight:not(:first-child) .card-img-bottom,.card-group>.card:not(:first-child) .card-footer,.td-content .card-group>.highlight:not(:first-child) .card-footer{border-bottom-left-radius:0}}.card-columns .card,.card-columns .td-content .highlight,.td-content .card-columns .highlight{margin-bottom:.75rem}@media(min-width:576px){.card-columns{-moz-column-count:3;column-count:3;-moz-column-gap:1.25rem;column-gap:1.25rem;orphans:1;widows:1}.card-columns .card,.card-columns .td-content .highlight,.td-content .card-columns .highlight{display:inline-block;width:100%}}.accordion{overflow-anchor:none}.accordion>.card,.td-content .accordion>.highlight{overflow:hidden}.accordion>.card:not(:last-of-type),.td-content .accordion>.highlight:not(:last-of-type){border-bottom:0;border-bottom-right-radius:0;border-bottom-left-radius:0}.accordion>.card:not(:first-of-type),.td-content .accordion>.highlight:not(:first-of-type){border-top-left-radius:0;border-top-right-radius:0}.accordion>.card>.card-header,.td-content .accordion>.highlight>.card-header{border-radius:0;margin-bottom:-1px}.breadcrumb{display:flex;flex-wrap:wrap;padding:.75rem 1rem;margin-bottom:1rem;list-style:none;background-color:#eee;border-radius:.25rem}.breadcrumb-item+.breadcrumb-item{padding-left:.5rem}.breadcrumb-item+.breadcrumb-item::before{float:left;padding-right:.5rem;color:#797676;content:"/"}.breadcrumb-item+.breadcrumb-item:hover::before{text-decoration:underline}.breadcrumb-item+.breadcrumb-item:hover::before{text-decoration:none}.breadcrumb-item.active{color:#797676}.pagination{display:flex;padding-left:0;list-style:none;border-radius:.25rem}.page-link{position:relative;display:block;padding:.5rem .75rem;margin-left:-1px;line-height:1.25;color:#797676;background-color:#fff;border:1px solid rgba(0,0,0,.1)}.page-link:hover{z-index:2;color:#1e53a0;text-decoration:none;background-color:#eee;border-color:#dee2e6}.page-link:focus{z-index:3;outline:0;box-shadow:0 0 0 .2rem rgba(48,99,142,.25)}.page-item:first-child .page-link{margin-left:0;border-top-left-radius:.25rem;border-bottom-left-radius:.25rem}.page-item:last-child .page-link{border-top-right-radius:.25rem;border-bottom-right-radius:.25rem}.page-item.active .page-link{z-index:3;color:#fff;background-color:#30638e;border-color:#2a567b}.page-item.disabled .page-link{color:#dee2e6;pointer-events:none;cursor:auto;background-color:#fff;border-color:#dee2e6}.pagination-lg .page-link{padding:.75rem 1.5rem;font-size:1.25rem;line-height:1.5}.pagination-lg .page-item:first-child .page-link{border-top-left-radius:.3rem;border-bottom-left-radius:.3rem}.pagination-lg .page-item:last-child .page-link{border-top-right-radius:.3rem;border-bottom-right-radius:.3rem}.pagination-sm .page-link{padding:.25rem .5rem;font-size:.875rem;line-height:1.5}.pagination-sm .page-item:first-child .page-link{border-top-left-radius:.2rem;border-bottom-left-radius:.2rem}.pagination-sm .page-item:last-child .page-link{border-top-right-radius:.2rem;border-bottom-right-radius:.2rem}.badge{display:inline-block;padding:.25em .4em;font-size:75%;font-weight:700;line-height:1;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25rem;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media(prefers-reduced-motion:reduce){.badge{transition:none}}a.badge:hover,a.badge:focus{text-decoration:none}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.badge-pill{padding-right:.6em;padding-left:.6em;border-radius:10rem}.badge-primary{color:#fff;background-color:#30638e}a.badge-primary:hover,a.badge-primary:focus{color:#fff;background-color:#234868}a.badge-primary:focus,a.badge-primary.focus{outline:0;box-shadow:0 0 0 .2rem rgba(48,99,142,.5)}.badge-secondary{color:#fff;background-color:#ffa630}a.badge-secondary:hover,a.badge-secondary:focus{color:#fff;background-color:#fc9000}a.badge-secondary:focus,a.badge-secondary.focus{outline:0;box-shadow:0 0 0 .2rem rgba(255,166,48,.5)}.badge-success{color:#fff;background-color:#3772ff}a.badge-success:hover,a.badge-success:focus{color:#fff;background-color:#044eff}a.badge-success:focus,a.badge-success.focus{outline:0;box-shadow:0 0 0 .2rem rgba(55,114,255,.5)}.badge-info{color:#222;background-color:#c0e0de}a.badge-info:hover,a.badge-info:focus{color:#222;background-color:#9ecfcc}a.badge-info:focus,a.badge-info.focus{outline:0;box-shadow:0 0 0 .2rem rgba(192,224,222,.5)}.badge-warning{color:#fff;background-color:#ed6a5a}a.badge-warning:hover,a.badge-warning:focus{color:#fff;background-color:#e8402c}a.badge-warning:focus,a.badge-warning.focus{outline:0;box-shadow:0 0 0 .2rem rgba(237,106,90,.5)}.badge-danger{color:#fff;background-color:#ed6a5a}a.badge-danger:hover,a.badge-danger:focus{color:#fff;background-color:#e8402c}a.badge-danger:focus,a.badge-danger.focus{outline:0;box-shadow:0 0 0 .2rem rgba(237,106,90,.5)}.badge-light{color:#222;background-color:#d3f3ee}a.badge-light:hover,a.badge-light:focus{color:#222;background-color:#abe8df}a.badge-light:focus,a.badge-light.focus{outline:0;box-shadow:0 0 0 .2rem rgba(211,243,238,.5)}.badge-dark{color:#fff;background-color:#403f4c}a.badge-dark:hover,a.badge-dark:focus{color:#fff;background-color:#292830}a.badge-dark:focus,a.badge-dark.focus{outline:0;box-shadow:0 0 0 .2rem rgba(64,63,76,.5)}.jumbotron{padding:2rem 1rem;margin-bottom:2rem;background-color:#eee;border-radius:.3rem}@media(min-width:576px){.jumbotron{padding:4rem 2rem}}.jumbotron-fluid{padding-right:0;padding-left:0;border-radius:0}.alert{position:relative;padding:.75rem 1.25rem;margin-bottom:1rem;border:1px solid transparent;border-radius:.25rem}.alert-heading{color:inherit}.alert-link{font-weight:700}.alert-dismissible{padding-right:4rem}.alert-dismissible .close{position:absolute;top:0;right:0;z-index:2;padding:.75rem 1.25rem;color:inherit}.alert-primary{color:#19334a;background:#d6e0e8 linear-gradient(180deg,#dce5eb,#d6e0e8)repeat-x;border-color:#c5d3df}.alert-primary hr{border-top-color:#b5c7d6}.alert-primary .alert-link{color:#0c1924}.alert-secondary{color:#855619;background:#ffedd6 linear-gradient(180deg,#fff0dc,#ffedd6)repeat-x;border-color:#ffe6c5}.alert-secondary hr{border-top-color:#ffdbac}.alert-secondary .alert-link{color:#5a3a11}.alert-success{color:#1d3b85;background:#d7e3ff linear-gradient(180deg,#dde7ff,#d7e3ff)repeat-x;border-color:#c7d8ff}.alert-success hr{border-top-color:#aec6ff}.alert-success .alert-link{color:#14285b}.alert-info{color:#647473;background:#f2f9f8 linear-gradient(180deg,#f4faf9,#f2f9f8)repeat-x;border-color:#edf6f6}.alert-info hr{border-top-color:#dceeee}.alert-info .alert-link{color:#4c5958}.alert-warning{color:#7b372f;background:#fbe1de linear-gradient(180deg,#fce6e3,#fbe1de)repeat-x;border-color:#fad5d1}.alert-warning hr{border-top-color:#f8c0ba}.alert-warning .alert-link{color:#562721}.alert-danger{color:#7b372f;background:#fbe1de linear-gradient(180deg,#fce6e3,#fbe1de)repeat-x;border-color:#fad5d1}.alert-danger hr{border-top-color:#f8c0ba}.alert-danger .alert-link{color:#562721}.alert-light{color:#6e7e7c;background:#f6fdfc linear-gradient(180deg,#f7fdfc,#f6fdfc)repeat-x;border-color:#f3fcfa}.alert-light hr{border-top-color:#dff7f2}.alert-light .alert-link{color:#566361}.alert-dark{color:#212128;background:#d9d9db linear-gradient(180deg,#dfdfe0,#d9d9db)repeat-x;border-color:#cac9cd}.alert-dark hr{border-top-color:#bdbcc1}.alert-dark .alert-link{color:#0a0a0c}@-webkit-keyframes progress-bar-stripes{from{background-position:1rem 0}to{background-position:0 0}}@keyframes progress-bar-stripes{from{background-position:1rem 0}to{background-position:0 0}}.progress{display:flex;height:1rem;overflow:hidden;line-height:0;font-size:.75rem;background-color:#eee;border-radius:.25rem;box-shadow:inset 0 .1rem .1rem rgba(0,0,0,.1)}.progress-bar{display:flex;flex-direction:column;justify-content:center;overflow:hidden;color:#fff;text-align:center;white-space:nowrap;background-color:#30638e;transition:width .6s ease}@media(prefers-reduced-motion:reduce){.progress-bar{transition:none}}.progress-bar-striped{background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-size:1rem 1rem}.progress-bar-animated{-webkit-animation:1s linear infinite progress-bar-stripes;animation:1s linear infinite progress-bar-stripes}@media(prefers-reduced-motion:reduce){.progress-bar-animated{-webkit-animation:none;animation:none}}.media{display:flex;align-items:flex-start}.media-body{flex:1}.list-group{display:flex;flex-direction:column;padding-left:0;margin-bottom:0;border-radius:.25rem}.list-group-item-action{width:100%;color:#495057;text-align:inherit}.list-group-item-action:hover,.list-group-item-action:focus{z-index:1;color:#495057;text-decoration:none;background-color:#f8f9fa}.list-group-item-action:active{color:#222;background-color:#eee}.list-group-item{position:relative;display:block;padding:.75rem 1.25rem;background-color:#fff;border:1px solid rgba(0,0,0,.125)}.list-group-item:first-child{border-top-left-radius:inherit;border-top-right-radius:inherit}.list-group-item:last-child{border-bottom-right-radius:inherit;border-bottom-left-radius:inherit}.list-group-item.disabled,.list-group-item:disabled{color:#797676;pointer-events:none;background-color:#fff}.list-group-item.active{z-index:2;color:#fff;background-color:#30638e;border-color:#30638e}.list-group-item+.list-group-item{border-top-width:0}.list-group-item+.list-group-item.active{margin-top:-1px;border-top-width:1px}.list-group-horizontal{flex-direction:row}.list-group-horizontal>.list-group-item:first-child{border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal>.list-group-item:last-child{border-top-right-radius:.25rem;border-bottom-left-radius:0}.list-group-horizontal>.list-group-item.active{margin-top:0}.list-group-horizontal>.list-group-item+.list-group-item{border-top-width:1px;border-left-width:0}.list-group-horizontal>.list-group-item+.list-group-item.active{margin-left:-1px;border-left-width:1px}@media(min-width:576px){.list-group-horizontal-sm{flex-direction:row}.list-group-horizontal-sm>.list-group-item:first-child{border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal-sm>.list-group-item:last-child{border-top-right-radius:.25rem;border-bottom-left-radius:0}.list-group-horizontal-sm>.list-group-item.active{margin-top:0}.list-group-horizontal-sm>.list-group-item+.list-group-item{border-top-width:1px;border-left-width:0}.list-group-horizontal-sm>.list-group-item+.list-group-item.active{margin-left:-1px;border-left-width:1px}}@media(min-width:768px){.list-group-horizontal-md{flex-direction:row}.list-group-horizontal-md>.list-group-item:first-child{border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal-md>.list-group-item:last-child{border-top-right-radius:.25rem;border-bottom-left-radius:0}.list-group-horizontal-md>.list-group-item.active{margin-top:0}.list-group-horizontal-md>.list-group-item+.list-group-item{border-top-width:1px;border-left-width:0}.list-group-horizontal-md>.list-group-item+.list-group-item.active{margin-left:-1px;border-left-width:1px}}@media(min-width:992px){.list-group-horizontal-lg{flex-direction:row}.list-group-horizontal-lg>.list-group-item:first-child{border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal-lg>.list-group-item:last-child{border-top-right-radius:.25rem;border-bottom-left-radius:0}.list-group-horizontal-lg>.list-group-item.active{margin-top:0}.list-group-horizontal-lg>.list-group-item+.list-group-item{border-top-width:1px;border-left-width:0}.list-group-horizontal-lg>.list-group-item+.list-group-item.active{margin-left:-1px;border-left-width:1px}}@media(min-width:1200px){.list-group-horizontal-xl{flex-direction:row}.list-group-horizontal-xl>.list-group-item:first-child{border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal-xl>.list-group-item:last-child{border-top-right-radius:.25rem;border-bottom-left-radius:0}.list-group-horizontal-xl>.list-group-item.active{margin-top:0}.list-group-horizontal-xl>.list-group-item+.list-group-item{border-top-width:1px;border-left-width:0}.list-group-horizontal-xl>.list-group-item+.list-group-item.active{margin-left:-1px;border-left-width:1px}}.list-group-flush{border-radius:0}.list-group-flush>.list-group-item{border-width:0 0 1px}.list-group-flush>.list-group-item:last-child{border-bottom-width:0}.list-group-item-primary{color:#19334a;background-color:#c5d3df}.list-group-item-primary.list-group-item-action:hover,.list-group-item-primary.list-group-item-action:focus{color:#19334a;background-color:#b5c7d6}.list-group-item-primary.list-group-item-action.active{color:#fff;background-color:#19334a;border-color:#19334a}.list-group-item-secondary{color:#855619;background-color:#ffe6c5}.list-group-item-secondary.list-group-item-action:hover,.list-group-item-secondary.list-group-item-action:focus{color:#855619;background-color:#ffdbac}.list-group-item-secondary.list-group-item-action.active{color:#fff;background-color:#855619;border-color:#855619}.list-group-item-success{color:#1d3b85;background-color:#c7d8ff}.list-group-item-success.list-group-item-action:hover,.list-group-item-success.list-group-item-action:focus{color:#1d3b85;background-color:#aec6ff}.list-group-item-success.list-group-item-action.active{color:#fff;background-color:#1d3b85;border-color:#1d3b85}.list-group-item-info{color:#647473;background-color:#edf6f6}.list-group-item-info.list-group-item-action:hover,.list-group-item-info.list-group-item-action:focus{color:#647473;background-color:#dceeee}.list-group-item-info.list-group-item-action.active{color:#fff;background-color:#647473;border-color:#647473}.list-group-item-warning{color:#7b372f;background-color:#fad5d1}.list-group-item-warning.list-group-item-action:hover,.list-group-item-warning.list-group-item-action:focus{color:#7b372f;background-color:#f8c0ba}.list-group-item-warning.list-group-item-action.active{color:#fff;background-color:#7b372f;border-color:#7b372f}.list-group-item-danger{color:#7b372f;background-color:#fad5d1}.list-group-item-danger.list-group-item-action:hover,.list-group-item-danger.list-group-item-action:focus{color:#7b372f;background-color:#f8c0ba}.list-group-item-danger.list-group-item-action.active{color:#fff;background-color:#7b372f;border-color:#7b372f}.list-group-item-light{color:#6e7e7c;background-color:#f3fcfa}.list-group-item-light.list-group-item-action:hover,.list-group-item-light.list-group-item-action:focus{color:#6e7e7c;background-color:#dff7f2}.list-group-item-light.list-group-item-action.active{color:#fff;background-color:#6e7e7c;border-color:#6e7e7c}.list-group-item-dark{color:#212128;background-color:#cac9cd}.list-group-item-dark.list-group-item-action:hover,.list-group-item-dark.list-group-item-action:focus{color:#212128;background-color:#bdbcc1}.list-group-item-dark.list-group-item-action.active{color:#fff;background-color:#212128;border-color:#212128}.close{float:right;font-size:1.5rem;font-weight:700;line-height:1;color:#000;text-shadow:0 1px 0 #fff;opacity:.5}.close:hover{color:#000;text-decoration:none}.close:not(:disabled):not(.disabled):hover,.close:not(:disabled):not(.disabled):focus{opacity:.75}button.close{padding:0;background-color:transparent;border:0}a.close.disabled{pointer-events:none}.toast{flex-basis:350px;max-width:350px;font-size:.875rem;background-color:rgba(255,255,255,.85);background-clip:padding-box;border:1px solid rgba(0,0,0,.1);box-shadow:0 .25rem .75rem rgba(0,0,0,.1);opacity:0;border-radius:.25rem}.toast:not(:last-child){margin-bottom:.75rem}.toast.showing{opacity:1}.toast.show{display:block;opacity:1}.toast.hide{display:none}.toast-header{display:flex;align-items:center;padding:.25rem .75rem;color:#797676;background-color:rgba(255,255,255,.85);background-clip:padding-box;border-bottom:1px solid rgba(0,0,0,5%);border-top-left-radius:calc(.25rem - 1px);border-top-right-radius:calc(.25rem - 1px)}.toast-body{padding:.75rem}.modal-open{overflow:hidden}.modal-open .modal{overflow-x:hidden;overflow-y:auto}.modal{position:fixed;top:0;left:0;z-index:1050;display:none;width:100%;height:100%;overflow:hidden;outline:0}.modal-dialog{position:relative;width:auto;margin:.5rem;pointer-events:none}.modal.fade .modal-dialog{transition:transform .3s ease-out;transform:translate(0,-50px)}@media(prefers-reduced-motion:reduce){.modal.fade .modal-dialog{transition:none}}.modal.show .modal-dialog{transform:none}.modal.modal-static .modal-dialog{transform:scale(1.02)}.modal-dialog-scrollable{display:flex;max-height:calc(100% - 1rem)}.modal-dialog-scrollable .modal-content{max-height:calc(100vh - 1rem);overflow:hidden}.modal-dialog-scrollable .modal-header,.modal-dialog-scrollable .modal-footer{flex-shrink:0}.modal-dialog-scrollable .modal-body{overflow-y:auto}.modal-dialog-centered{display:flex;align-items:center;min-height:calc(100% - 1rem)}.modal-dialog-centered::before{display:block;height:calc(100vh - 1rem);height:-webkit-min-content;height:-moz-min-content;height:min-content;content:""}.modal-dialog-centered.modal-dialog-scrollable{flex-direction:column;justify-content:center;height:100%}.modal-dialog-centered.modal-dialog-scrollable .modal-content{max-height:none}.modal-dialog-centered.modal-dialog-scrollable::before{content:none}.modal-content{position:relative;display:flex;flex-direction:column;width:100%;pointer-events:auto;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,.2);border-radius:.3rem;box-shadow:0 .25rem .5rem rgba(0,0,0,.5);outline:0}.modal-backdrop{position:fixed;top:0;left:0;z-index:1040;width:100vw;height:100vh;background-color:#000}.modal-backdrop.fade{opacity:0}.modal-backdrop.show{opacity:.5}.modal-header{display:flex;align-items:flex-start;justify-content:space-between;padding:1rem;border-bottom:1px solid #dee2e6;border-top-left-radius:calc(.3rem - 1px);border-top-right-radius:calc(.3rem - 1px)}.modal-header .close{padding:1rem;margin:-1rem -1rem -1rem auto}.modal-title{margin-bottom:0;line-height:1.5}.modal-body{position:relative;flex:auto;padding:1rem}.modal-footer{display:flex;flex-wrap:wrap;align-items:center;justify-content:flex-end;padding:.75rem;border-top:1px solid #dee2e6;border-bottom-right-radius:calc(.3rem - 1px);border-bottom-left-radius:calc(.3rem - 1px)}.modal-footer>*{margin:.25rem}.modal-scrollbar-measure{position:absolute;top:-9999px;width:50px;height:50px;overflow:scroll}@media(min-width:576px){.modal-dialog{max-width:500px;margin:1.75rem auto}.modal-dialog-scrollable{max-height:calc(100% - 3.5rem)}.modal-dialog-scrollable .modal-content{max-height:calc(100vh - 3.5rem)}.modal-dialog-centered{min-height:calc(100% - 3.5rem)}.modal-dialog-centered::before{height:calc(100vh - 3.5rem);height:-webkit-min-content;height:-moz-min-content;height:min-content}.modal-content{box-shadow:0 .5rem 1rem rgba(0,0,0,.5)}.modal-sm{max-width:300px}}@media(min-width:992px){.modal-lg,.modal-xl{max-width:800px}}@media(min-width:1200px){.modal-xl{max-width:1140px}}.tooltip{position:absolute;z-index:1070;display:block;margin:0;font-family:open sans,-apple-system,BlinkMacSystemFont,segoe ui,Roboto,helvetica neue,Arial,sans-serif,apple color emoji,segoe ui emoji,segoe ui symbol;font-style:normal;font-weight:400;line-height:1.5;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;white-space:normal;line-break:auto;font-size:.875rem;word-wrap:break-word;opacity:0}.tooltip.show{opacity:.9}.tooltip .arrow{position:absolute;display:block;width:.8rem;height:.4rem}.tooltip .arrow::before{position:absolute;content:"";border-color:transparent;border-style:solid}.bs-tooltip-top,.bs-tooltip-auto[x-placement^=top]{padding:.4rem 0}.bs-tooltip-top .arrow,.bs-tooltip-auto[x-placement^=top] .arrow{bottom:0}.bs-tooltip-top .arrow::before,.bs-tooltip-auto[x-placement^=top] .arrow::before{top:0;border-width:.4rem .4rem 0;border-top-color:#000}.bs-tooltip-right,.bs-tooltip-auto[x-placement^=right]{padding:0 .4rem}.bs-tooltip-right .arrow,.bs-tooltip-auto[x-placement^=right] .arrow{left:0;width:.4rem;height:.8rem}.bs-tooltip-right .arrow::before,.bs-tooltip-auto[x-placement^=right] .arrow::before{right:0;border-width:.4rem .4rem .4rem 0;border-right-color:#000}.bs-tooltip-bottom,.bs-tooltip-auto[x-placement^=bottom]{padding:.4rem 0}.bs-tooltip-bottom .arrow,.bs-tooltip-auto[x-placement^=bottom] .arrow{top:0}.bs-tooltip-bottom .arrow::before,.bs-tooltip-auto[x-placement^=bottom] .arrow::before{bottom:0;border-width:0 .4rem .4rem;border-bottom-color:#000}.bs-tooltip-left,.bs-tooltip-auto[x-placement^=left]{padding:0 .4rem}.bs-tooltip-left .arrow,.bs-tooltip-auto[x-placement^=left] .arrow{right:0;width:.4rem;height:.8rem}.bs-tooltip-left .arrow::before,.bs-tooltip-auto[x-placement^=left] .arrow::before{left:0;border-width:.4rem 0 .4rem .4rem;border-left-color:#000}.tooltip-inner{max-width:200px;padding:.25rem .5rem;color:#fff;text-align:center;background-color:#000;border-radius:.25rem}.popover{position:absolute;top:0;left:0;z-index:1060;display:block;max-width:276px;font-family:open sans,-apple-system,BlinkMacSystemFont,segoe ui,Roboto,helvetica neue,Arial,sans-serif,apple color emoji,segoe ui emoji,segoe ui symbol;font-style:normal;font-weight:400;line-height:1.5;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;white-space:normal;line-break:auto;font-size:.875rem;word-wrap:break-word;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,.2);border-radius:.3rem;box-shadow:0 .25rem .5rem rgba(0,0,0,.2)}.popover .arrow{position:absolute;display:block;width:1rem;height:.5rem;margin:0 .3rem}.popover .arrow::before,.popover .arrow::after{position:absolute;display:block;content:"";border-color:transparent;border-style:solid}.bs-popover-top,.bs-popover-auto[x-placement^=top]{margin-bottom:.5rem}.bs-popover-top>.arrow,.bs-popover-auto[x-placement^=top]>.arrow{bottom:calc(-.5rem - 1px)}.bs-popover-top>.arrow::before,.bs-popover-auto[x-placement^=top]>.arrow::before{bottom:0;border-width:.5rem .5rem 0;border-top-color:rgba(0,0,0,.25)}.bs-popover-top>.arrow::after,.bs-popover-auto[x-placement^=top]>.arrow::after{bottom:1px;border-width:.5rem .5rem 0;border-top-color:#fff}.bs-popover-right,.bs-popover-auto[x-placement^=right]{margin-left:.5rem}.bs-popover-right>.arrow,.bs-popover-auto[x-placement^=right]>.arrow{left:calc(-.5rem - 1px);width:.5rem;height:1rem;margin:.3rem 0}.bs-popover-right>.arrow::before,.bs-popover-auto[x-placement^=right]>.arrow::before{left:0;border-width:.5rem .5rem .5rem 0;border-right-color:rgba(0,0,0,.25)}.bs-popover-right>.arrow::after,.bs-popover-auto[x-placement^=right]>.arrow::after{left:1px;border-width:.5rem .5rem .5rem 0;border-right-color:#fff}.bs-popover-bottom,.bs-popover-auto[x-placement^=bottom]{margin-top:.5rem}.bs-popover-bottom>.arrow,.bs-popover-auto[x-placement^=bottom]>.arrow{top:calc(-.5rem - 1px)}.bs-popover-bottom>.arrow::before,.bs-popover-auto[x-placement^=bottom]>.arrow::before{top:0;border-width:0 .5rem .5rem;border-bottom-color:rgba(0,0,0,.25)}.bs-popover-bottom>.arrow::after,.bs-popover-auto[x-placement^=bottom]>.arrow::after{top:1px;border-width:0 .5rem .5rem;border-bottom-color:#fff}.bs-popover-bottom .popover-header::before,.bs-popover-auto[x-placement^=bottom] .popover-header::before{position:absolute;top:0;left:50%;display:block;width:1rem;margin-left:-.5rem;content:"";border-bottom:1px solid #f7f7f7}.bs-popover-left,.bs-popover-auto[x-placement^=left]{margin-right:.5rem}.bs-popover-left>.arrow,.bs-popover-auto[x-placement^=left]>.arrow{right:calc(-.5rem - 1px);width:.5rem;height:1rem;margin:.3rem 0}.bs-popover-left>.arrow::before,.bs-popover-auto[x-placement^=left]>.arrow::before{right:0;border-width:.5rem 0 .5rem .5rem;border-left-color:rgba(0,0,0,.25)}.bs-popover-left>.arrow::after,.bs-popover-auto[x-placement^=left]>.arrow::after{right:1px;border-width:.5rem 0 .5rem .5rem;border-left-color:#fff}.popover-header{padding:.5rem .75rem;margin-bottom:0;font-size:1rem;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;border-top-left-radius:calc(.3rem - 1px);border-top-right-radius:calc(.3rem - 1px)}.popover-header:empty{display:none}.popover-body{padding:.5rem .75rem;color:#222}.carousel{position:relative}.carousel.pointer-event{touch-action:pan-y}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-inner::after{display:block;clear:both;content:""}.carousel-item{position:relative;display:none;float:left;width:100%;margin-right:-100%;-webkit-backface-visibility:hidden;backface-visibility:hidden;transition:transform .6s ease-in-out}@media(prefers-reduced-motion:reduce){.carousel-item{transition:none}}.carousel-item.active,.carousel-item-next,.carousel-item-prev{display:block}.carousel-item-next:not(.carousel-item-left),.active.carousel-item-right{transform:translateX(100%)}.carousel-item-prev:not(.carousel-item-right),.active.carousel-item-left{transform:translateX(-100%)}.carousel-fade .carousel-item{opacity:0;transition-property:opacity;transform:none}.carousel-fade .carousel-item.active,.carousel-fade .carousel-item-next.carousel-item-left,.carousel-fade .carousel-item-prev.carousel-item-right{z-index:1;opacity:1}.carousel-fade .active.carousel-item-left,.carousel-fade .active.carousel-item-right{z-index:0;opacity:0;transition:opacity 0s .6s}@media(prefers-reduced-motion:reduce){.carousel-fade .active.carousel-item-left,.carousel-fade .active.carousel-item-right{transition:none}}.carousel-control-prev,.carousel-control-next{position:absolute;top:0;bottom:0;z-index:1;display:flex;align-items:center;justify-content:center;width:15%;padding:0;color:#fff;text-align:center;background:0 0;border:0;opacity:.5;transition:opacity .15s ease}@media(prefers-reduced-motion:reduce){.carousel-control-prev,.carousel-control-next{transition:none}}.carousel-control-prev:hover,.carousel-control-prev:focus,.carousel-control-next:hover,.carousel-control-next:focus{color:#fff;text-decoration:none;outline:0;opacity:.9}.carousel-control-prev{left:0;background-image:linear-gradient(90deg,rgba(0,0,0,.25),rgba(0,0,0,.1%))}.carousel-control-next{right:0;background-image:linear-gradient(270deg,rgba(0,0,0,.25),rgba(0,0,0,.1%))}.carousel-control-prev-icon,.carousel-control-next-icon{display:inline-block;width:20px;height:20px;background:50%/100% 100% no-repeat}.carousel-control-prev-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='%23fff' width='8' height='8' viewBox='0 0 8 8'%3e%3cpath d='M5.25 0l-4 4 4 4 1.5-1.5L4.25 4l2.5-2.5L5.25 0z'/%3e%3c/svg%3e")}.carousel-control-next-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='%23fff' width='8' height='8' viewBox='0 0 8 8'%3e%3cpath d='M2.75 0l-1.5 1.5L3.75 4l-2.5 2.5L2.75 8l4-4-4-4z'/%3e%3c/svg%3e")}.carousel-indicators{position:absolute;right:0;bottom:0;left:0;z-index:15;display:flex;justify-content:center;padding-left:0;margin-right:15%;margin-left:15%;list-style:none}.carousel-indicators li{box-sizing:content-box;flex:initial;width:30px;height:3px;margin-right:3px;margin-left:3px;text-indent:-999px;cursor:pointer;background-color:#fff;background-clip:padding-box;border-top:10px solid transparent;border-bottom:10px solid transparent;opacity:.5;transition:opacity .6s ease}@media(prefers-reduced-motion:reduce){.carousel-indicators li{transition:none}}.carousel-indicators .active{opacity:1}.carousel-caption{position:absolute;right:15%;bottom:20px;left:15%;z-index:10;padding-top:20px;padding-bottom:20px;color:#fff;text-align:center}@-webkit-keyframes spinner-border{to{transform:rotate(360deg)}}@keyframes spinner-border{to{transform:rotate(360deg)}}.spinner-border{display:inline-block;width:2rem;height:2rem;vertical-align:-.125em;border:.25em solid;border-right-color:transparent;border-radius:50%;-webkit-animation:.75s linear infinite spinner-border;animation:.75s linear infinite spinner-border}.spinner-border-sm{width:1rem;height:1rem;border-width:.2em}@-webkit-keyframes spinner-grow{0%{transform:scale(0)}50%{opacity:1;transform:none}}@keyframes spinner-grow{0%{transform:scale(0)}50%{opacity:1;transform:none}}.spinner-grow{display:inline-block;width:2rem;height:2rem;vertical-align:-.125em;background-color:currentColor;border-radius:50%;opacity:0;-webkit-animation:.75s linear infinite spinner-grow;animation:.75s linear infinite spinner-grow}.spinner-grow-sm{width:1rem;height:1rem}@media(prefers-reduced-motion:reduce){.spinner-border,.spinner-grow{-webkit-animation-duration:1.5s;animation-duration:1.5s}}.align-baseline{vertical-align:baseline!important}.align-top{vertical-align:top!important}.align-middle{vertical-align:middle!important}.align-bottom{vertical-align:bottom!important}.align-text-bottom{vertical-align:text-bottom!important}.align-text-top{vertical-align:text-top!important}.bg-primary{background-color:#30638e!important}a.bg-primary:hover,a.bg-primary:focus,button.bg-primary:hover,button.bg-primary:focus{background-color:#234868!important}.bg-secondary{background-color:#ffa630!important}a.bg-secondary:hover,a.bg-secondary:focus,button.bg-secondary:hover,button.bg-secondary:focus{background-color:#fc9000!important}.bg-success{background-color:#3772ff!important}a.bg-success:hover,a.bg-success:focus,button.bg-success:hover,button.bg-success:focus{background-color:#044eff!important}.bg-info{background-color:#c0e0de!important}a.bg-info:hover,a.bg-info:focus,button.bg-info:hover,button.bg-info:focus{background-color:#9ecfcc!important}.bg-warning{background-color:#ed6a5a!important}a.bg-warning:hover,a.bg-warning:focus,button.bg-warning:hover,button.bg-warning:focus{background-color:#e8402c!important}.bg-danger{background-color:#ed6a5a!important}a.bg-danger:hover,a.bg-danger:focus,button.bg-danger:hover,button.bg-danger:focus{background-color:#e8402c!important}.bg-light{background-color:#d3f3ee!important}a.bg-light:hover,a.bg-light:focus,button.bg-light:hover,button.bg-light:focus{background-color:#abe8df!important}.bg-dark{background-color:#403f4c!important}a.bg-dark:hover,a.bg-dark:focus,button.bg-dark:hover,button.bg-dark:focus{background-color:#292830!important}.bg-gradient-primary{background:#30638e linear-gradient(180deg,#4f7a9f,#30638E)repeat-x!important}.bg-gradient-secondary{background:#ffa630 linear-gradient(180deg,#ffb34f,#FFA630)repeat-x!important}.bg-gradient-success{background:#3772ff linear-gradient(180deg,#5587ff,#3772FF)repeat-x!important}.bg-gradient-info{background:#c0e0de linear-gradient(180deg,#c9e5e3,#C0E0DE)repeat-x!important}.bg-gradient-warning{background:#ed6a5a linear-gradient(180deg,#f08073,#ED6A5A)repeat-x!important}.bg-gradient-danger{background:#ed6a5a linear-gradient(180deg,#f08073,#ED6A5A)repeat-x!important}.bg-gradient-light{background:#d3f3ee linear-gradient(180deg,#daf5f1,#D3F3EE)repeat-x!important}.bg-gradient-dark{background:#403f4c linear-gradient(180deg,#5d5c67,#403F4C)repeat-x!important}.bg-white{background-color:#fff!important}.bg-transparent{background-color:transparent!important}.border{border:1px solid #dee2e6!important}.border-top{border-top:1px solid #dee2e6!important}.border-right{border-right:1px solid #dee2e6!important}.border-bottom{border-bottom:1px solid #dee2e6!important}.border-left{border-left:1px solid #dee2e6!important}.border-0{border:0!important}.border-top-0{border-top:0!important}.border-right-0{border-right:0!important}.border-bottom-0{border-bottom:0!important}.border-left-0{border-left:0!important}.border-primary{border-color:#30638e!important}.border-secondary{border-color:#ffa630!important}.border-success{border-color:#3772ff!important}.border-info{border-color:#c0e0de!important}.border-warning{border-color:#ed6a5a!important}.border-danger{border-color:#ed6a5a!important}.border-light{border-color:#d3f3ee!important}.border-dark{border-color:#403f4c!important}.border-white{border-color:#fff!important}.rounded-sm{border-radius:.2rem!important}.rounded{border-radius:.25rem!important}.rounded-top{border-top-left-radius:.25rem!important;border-top-right-radius:.25rem!important}.rounded-right{border-top-right-radius:.25rem!important;border-bottom-right-radius:.25rem!important}.rounded-bottom{border-bottom-right-radius:.25rem!important;border-bottom-left-radius:.25rem!important}.rounded-left{border-top-left-radius:.25rem!important;border-bottom-left-radius:.25rem!important}.rounded-lg{border-radius:.3rem!important}.rounded-circle{border-radius:50%!important}.rounded-pill{border-radius:50rem!important}.rounded-0{border-radius:0!important}.clearfix::after{display:block;clear:both;content:""}.d-none{display:none!important}.d-inline{display:inline!important}.d-inline-block{display:inline-block!important}.d-block{display:block!important}.d-table{display:table!important}.d-table-row{display:table-row!important}.d-table-cell{display:table-cell!important}.d-flex{display:flex!important}.d-inline-flex{display:inline-flex!important}@media(min-width:576px){.d-sm-none{display:none!important}.d-sm-inline{display:inline!important}.d-sm-inline-block{display:inline-block!important}.d-sm-block{display:block!important}.d-sm-table{display:table!important}.d-sm-table-row{display:table-row!important}.d-sm-table-cell{display:table-cell!important}.d-sm-flex{display:flex!important}.d-sm-inline-flex{display:inline-flex!important}}@media(min-width:768px){.d-md-none{display:none!important}.d-md-inline{display:inline!important}.d-md-inline-block{display:inline-block!important}.d-md-block{display:block!important}.d-md-table{display:table!important}.d-md-table-row{display:table-row!important}.d-md-table-cell{display:table-cell!important}.d-md-flex{display:flex!important}.d-md-inline-flex{display:inline-flex!important}}@media(min-width:992px){.d-lg-none{display:none!important}.d-lg-inline{display:inline!important}.d-lg-inline-block{display:inline-block!important}.d-lg-block{display:block!important}.d-lg-table{display:table!important}.d-lg-table-row{display:table-row!important}.d-lg-table-cell{display:table-cell!important}.d-lg-flex{display:flex!important}.d-lg-inline-flex{display:inline-flex!important}}@media(min-width:1200px){.d-xl-none{display:none!important}.d-xl-inline{display:inline!important}.d-xl-inline-block{display:inline-block!important}.d-xl-block{display:block!important}.d-xl-table{display:table!important}.d-xl-table-row{display:table-row!important}.d-xl-table-cell{display:table-cell!important}.d-xl-flex{display:flex!important}.d-xl-inline-flex{display:inline-flex!important}}@media print{.d-print-none{display:none!important}.d-print-inline{display:inline!important}.d-print-inline-block{display:inline-block!important}.d-print-block{display:block!important}.d-print-table{display:table!important}.d-print-table-row{display:table-row!important}.d-print-table-cell{display:table-cell!important}.d-print-flex{display:flex!important}.d-print-inline-flex{display:inline-flex!important}}.embed-responsive{position:relative;display:block;width:100%;padding:0;overflow:hidden}.embed-responsive::before{display:block;content:""}.embed-responsive .embed-responsive-item,.embed-responsive iframe,.embed-responsive embed,.embed-responsive object,.embed-responsive video{position:absolute;top:0;bottom:0;left:0;width:100%;height:100%;border:0}.embed-responsive-21by9::before{padding-top:42.85714286%}.embed-responsive-16by9::before{padding-top:56.25%}.embed-responsive-4by3::before{padding-top:75%}.embed-responsive-1by1::before{padding-top:100%}.flex-row{flex-direction:row!important}.flex-column{flex-direction:column!important}.flex-row-reverse{flex-direction:row-reverse!important}.flex-column-reverse{flex-direction:column-reverse!important}.flex-wrap{flex-wrap:wrap!important}.flex-nowrap{flex-wrap:nowrap!important}.flex-wrap-reverse{flex-wrap:wrap-reverse!important}.flex-fill{flex:auto!important}.flex-grow-0{flex-grow:0!important}.flex-grow-1{flex-grow:1!important}.flex-shrink-0{flex-shrink:0!important}.flex-shrink-1{flex-shrink:1!important}.justify-content-start{justify-content:flex-start!important}.justify-content-end{justify-content:flex-end!important}.justify-content-center{justify-content:center!important}.justify-content-between{justify-content:space-between!important}.justify-content-around{justify-content:space-around!important}.align-items-start{align-items:flex-start!important}.align-items-end{align-items:flex-end!important}.align-items-center{align-items:center!important}.align-items-baseline{align-items:baseline!important}.align-items-stretch{align-items:stretch!important}.align-content-start{align-content:flex-start!important}.align-content-end{align-content:flex-end!important}.align-content-center{align-content:center!important}.align-content-between{align-content:space-between!important}.align-content-around{align-content:space-around!important}.align-content-stretch{align-content:stretch!important}.align-self-auto{align-self:auto!important}.align-self-start{align-self:flex-start!important}.align-self-end{align-self:flex-end!important}.align-self-center{align-self:center!important}.align-self-baseline{align-self:baseline!important}.align-self-stretch{align-self:stretch!important}@media(min-width:576px){.flex-sm-row{flex-direction:row!important}.flex-sm-column{flex-direction:column!important}.flex-sm-row-reverse{flex-direction:row-reverse!important}.flex-sm-column-reverse{flex-direction:column-reverse!important}.flex-sm-wrap{flex-wrap:wrap!important}.flex-sm-nowrap{flex-wrap:nowrap!important}.flex-sm-wrap-reverse{flex-wrap:wrap-reverse!important}.flex-sm-fill{flex:auto!important}.flex-sm-grow-0{flex-grow:0!important}.flex-sm-grow-1{flex-grow:1!important}.flex-sm-shrink-0{flex-shrink:0!important}.flex-sm-shrink-1{flex-shrink:1!important}.justify-content-sm-start{justify-content:flex-start!important}.justify-content-sm-end{justify-content:flex-end!important}.justify-content-sm-center{justify-content:center!important}.justify-content-sm-between{justify-content:space-between!important}.justify-content-sm-around{justify-content:space-around!important}.align-items-sm-start{align-items:flex-start!important}.align-items-sm-end{align-items:flex-end!important}.align-items-sm-center{align-items:center!important}.align-items-sm-baseline{align-items:baseline!important}.align-items-sm-stretch{align-items:stretch!important}.align-content-sm-start{align-content:flex-start!important}.align-content-sm-end{align-content:flex-end!important}.align-content-sm-center{align-content:center!important}.align-content-sm-between{align-content:space-between!important}.align-content-sm-around{align-content:space-around!important}.align-content-sm-stretch{align-content:stretch!important}.align-self-sm-auto{align-self:auto!important}.align-self-sm-start{align-self:flex-start!important}.align-self-sm-end{align-self:flex-end!important}.align-self-sm-center{align-self:center!important}.align-self-sm-baseline{align-self:baseline!important}.align-self-sm-stretch{align-self:stretch!important}}@media(min-width:768px){.flex-md-row{flex-direction:row!important}.flex-md-column{flex-direction:column!important}.flex-md-row-reverse{flex-direction:row-reverse!important}.flex-md-column-reverse{flex-direction:column-reverse!important}.flex-md-wrap{flex-wrap:wrap!important}.flex-md-nowrap{flex-wrap:nowrap!important}.flex-md-wrap-reverse{flex-wrap:wrap-reverse!important}.flex-md-fill{flex:auto!important}.flex-md-grow-0{flex-grow:0!important}.flex-md-grow-1{flex-grow:1!important}.flex-md-shrink-0{flex-shrink:0!important}.flex-md-shrink-1{flex-shrink:1!important}.justify-content-md-start{justify-content:flex-start!important}.justify-content-md-end{justify-content:flex-end!important}.justify-content-md-center{justify-content:center!important}.justify-content-md-between{justify-content:space-between!important}.justify-content-md-around{justify-content:space-around!important}.align-items-md-start{align-items:flex-start!important}.align-items-md-end{align-items:flex-end!important}.align-items-md-center{align-items:center!important}.align-items-md-baseline{align-items:baseline!important}.align-items-md-stretch{align-items:stretch!important}.align-content-md-start{align-content:flex-start!important}.align-content-md-end{align-content:flex-end!important}.align-content-md-center{align-content:center!important}.align-content-md-between{align-content:space-between!important}.align-content-md-around{align-content:space-around!important}.align-content-md-stretch{align-content:stretch!important}.align-self-md-auto{align-self:auto!important}.align-self-md-start{align-self:flex-start!important}.align-self-md-end{align-self:flex-end!important}.align-self-md-center{align-self:center!important}.align-self-md-baseline{align-self:baseline!important}.align-self-md-stretch{align-self:stretch!important}}@media(min-width:992px){.flex-lg-row{flex-direction:row!important}.flex-lg-column{flex-direction:column!important}.flex-lg-row-reverse{flex-direction:row-reverse!important}.flex-lg-column-reverse{flex-direction:column-reverse!important}.flex-lg-wrap{flex-wrap:wrap!important}.flex-lg-nowrap{flex-wrap:nowrap!important}.flex-lg-wrap-reverse{flex-wrap:wrap-reverse!important}.flex-lg-fill{flex:auto!important}.flex-lg-grow-0{flex-grow:0!important}.flex-lg-grow-1{flex-grow:1!important}.flex-lg-shrink-0{flex-shrink:0!important}.flex-lg-shrink-1{flex-shrink:1!important}.justify-content-lg-start{justify-content:flex-start!important}.justify-content-lg-end{justify-content:flex-end!important}.justify-content-lg-center{justify-content:center!important}.justify-content-lg-between{justify-content:space-between!important}.justify-content-lg-around{justify-content:space-around!important}.align-items-lg-start{align-items:flex-start!important}.align-items-lg-end{align-items:flex-end!important}.align-items-lg-center{align-items:center!important}.align-items-lg-baseline{align-items:baseline!important}.align-items-lg-stretch{align-items:stretch!important}.align-content-lg-start{align-content:flex-start!important}.align-content-lg-end{align-content:flex-end!important}.align-content-lg-center{align-content:center!important}.align-content-lg-between{align-content:space-between!important}.align-content-lg-around{align-content:space-around!important}.align-content-lg-stretch{align-content:stretch!important}.align-self-lg-auto{align-self:auto!important}.align-self-lg-start{align-self:flex-start!important}.align-self-lg-end{align-self:flex-end!important}.align-self-lg-center{align-self:center!important}.align-self-lg-baseline{align-self:baseline!important}.align-self-lg-stretch{align-self:stretch!important}}@media(min-width:1200px){.flex-xl-row{flex-direction:row!important}.flex-xl-column{flex-direction:column!important}.flex-xl-row-reverse{flex-direction:row-reverse!important}.flex-xl-column-reverse{flex-direction:column-reverse!important}.flex-xl-wrap{flex-wrap:wrap!important}.flex-xl-nowrap{flex-wrap:nowrap!important}.flex-xl-wrap-reverse{flex-wrap:wrap-reverse!important}.flex-xl-fill{flex:auto!important}.flex-xl-grow-0{flex-grow:0!important}.flex-xl-grow-1{flex-grow:1!important}.flex-xl-shrink-0{flex-shrink:0!important}.flex-xl-shrink-1{flex-shrink:1!important}.justify-content-xl-start{justify-content:flex-start!important}.justify-content-xl-end{justify-content:flex-end!important}.justify-content-xl-center{justify-content:center!important}.justify-content-xl-between{justify-content:space-between!important}.justify-content-xl-around{justify-content:space-around!important}.align-items-xl-start{align-items:flex-start!important}.align-items-xl-end{align-items:flex-end!important}.align-items-xl-center{align-items:center!important}.align-items-xl-baseline{align-items:baseline!important}.align-items-xl-stretch{align-items:stretch!important}.align-content-xl-start{align-content:flex-start!important}.align-content-xl-end{align-content:flex-end!important}.align-content-xl-center{align-content:center!important}.align-content-xl-between{align-content:space-between!important}.align-content-xl-around{align-content:space-around!important}.align-content-xl-stretch{align-content:stretch!important}.align-self-xl-auto{align-self:auto!important}.align-self-xl-start{align-self:flex-start!important}.align-self-xl-end{align-self:flex-end!important}.align-self-xl-center{align-self:center!important}.align-self-xl-baseline{align-self:baseline!important}.align-self-xl-stretch{align-self:stretch!important}}.float-left{float:left!important}.float-right{float:right!important}.float-none{float:none!important}@media(min-width:576px){.float-sm-left{float:left!important}.float-sm-right{float:right!important}.float-sm-none{float:none!important}}@media(min-width:768px){.float-md-left{float:left!important}.float-md-right{float:right!important}.float-md-none{float:none!important}}@media(min-width:992px){.float-lg-left{float:left!important}.float-lg-right{float:right!important}.float-lg-none{float:none!important}}@media(min-width:1200px){.float-xl-left{float:left!important}.float-xl-right{float:right!important}.float-xl-none{float:none!important}}.user-select-all{-webkit-user-select:all!important;-moz-user-select:all!important;user-select:all!important}.user-select-auto{-webkit-user-select:auto!important;-moz-user-select:auto!important;-ms-user-select:auto!important;user-select:auto!important}.user-select-none{-webkit-user-select:none!important;-moz-user-select:none!important;-ms-user-select:none!important;user-select:none!important}.overflow-auto{overflow:auto!important}.overflow-hidden{overflow:hidden!important}.position-static{position:static!important}.position-relative{position:relative!important}.position-absolute{position:absolute!important}.position-fixed{position:fixed!important}.position-sticky{position:-webkit-sticky!important;position:sticky!important}.fixed-top{position:fixed;top:0;right:0;left:0;z-index:1030}.fixed-bottom{position:fixed;right:0;bottom:0;left:0;z-index:1030}@supports((position:-webkit-sticky) or (position:sticky)){.sticky-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;overflow:visible;clip:auto;white-space:normal}.shadow-sm{box-shadow:0 .125rem .25rem rgba(0,0,0,.075)!important}.shadow{box-shadow:0 .5rem 1rem rgba(0,0,0,.15)!important}.shadow-lg{box-shadow:0 1rem 3rem rgba(0,0,0,.175)!important}.shadow-none{box-shadow:none!important}.w-25{width:25%!important}.w-50{width:50%!important}.w-75{width:75%!important}.w-100{width:100%!important}.w-auto{width:auto!important}.h-25{height:25%!important}.h-50{height:50%!important}.h-75{height:75%!important}.h-100{height:100%!important}.h-auto{height:auto!important}.mw-100{max-width:100%!important}.mh-100{max-height:100%!important}.min-vw-100{min-width:100vw!important}.min-vh-100{min-height:100vh!important}.vw-100{width:100vw!important}.vh-100{height:100vh!important}.m-0{margin:0!important}.mt-0,.my-0{margin-top:0!important}.mr-0,.mx-0{margin-right:0!important}.mb-0,.my-0{margin-bottom:0!important}.ml-0,.mx-0{margin-left:0!important}.m-1{margin:.25rem!important}.mt-1,.my-1{margin-top:.25rem!important}.mr-1,.mx-1{margin-right:.25rem!important}.mb-1,.my-1{margin-bottom:.25rem!important}.ml-1,.mx-1{margin-left:.25rem!important}.m-2{margin:.5rem!important}.mt-2,.my-2{margin-top:.5rem!important}.mr-2,.mx-2{margin-right:.5rem!important}.mb-2,.my-2{margin-bottom:.5rem!important}.ml-2,.mx-2{margin-left:.5rem!important}.m-3{margin:1rem!important}.mt-3,.my-3{margin-top:1rem!important}.mr-3,.mx-3{margin-right:1rem!important}.mb-3,.my-3{margin-bottom:1rem!important}.ml-3,.mx-3{margin-left:1rem!important}.m-4{margin:1.5rem!important}.mt-4,.my-4{margin-top:1.5rem!important}.mr-4,.mx-4{margin-right:1.5rem!important}.mb-4,.my-4{margin-bottom:1.5rem!important}.ml-4,.mx-4{margin-left:1.5rem!important}.m-5{margin:3rem!important}.mt-5,.my-5{margin-top:3rem!important}.mr-5,.mx-5{margin-right:3rem!important}.mb-5,.my-5{margin-bottom:3rem!important}.ml-5,.mx-5{margin-left:3rem!important}.p-0{padding:0!important}.pt-0,.py-0{padding-top:0!important}.pr-0,.px-0{padding-right:0!important}.pb-0,.py-0{padding-bottom:0!important}.pl-0,.px-0{padding-left:0!important}.p-1{padding:.25rem!important}.pt-1,.py-1{padding-top:.25rem!important}.pr-1,.px-1{padding-right:.25rem!important}.pb-1,.py-1{padding-bottom:.25rem!important}.pl-1,.px-1{padding-left:.25rem!important}.p-2{padding:.5rem!important}.pt-2,.py-2{padding-top:.5rem!important}.pr-2,.px-2{padding-right:.5rem!important}.pb-2,.py-2{padding-bottom:.5rem!important}.pl-2,.px-2{padding-left:.5rem!important}.p-3{padding:1rem!important}.pt-3,.py-3{padding-top:1rem!important}.pr-3,.px-3{padding-right:1rem!important}.pb-3,.py-3{padding-bottom:1rem!important}.pl-3,.px-3{padding-left:1rem!important}.p-4{padding:1.5rem!important}.pt-4,.py-4{padding-top:1.5rem!important}.pr-4,.px-4{padding-right:1.5rem!important}.pb-4,.py-4{padding-bottom:1.5rem!important}.pl-4,.px-4{padding-left:1.5rem!important}.p-5{padding:3rem!important}.pt-5,.py-5{padding-top:3rem!important}.pr-5,.px-5{padding-right:3rem!important}.pb-5,.py-5{padding-bottom:3rem!important}.pl-5,.px-5{padding-left:3rem!important}.m-n1{margin:-.25rem!important}.mt-n1,.my-n1{margin-top:-.25rem!important}.mr-n1,.mx-n1{margin-right:-.25rem!important}.mb-n1,.my-n1{margin-bottom:-.25rem!important}.ml-n1,.mx-n1{margin-left:-.25rem!important}.m-n2{margin:-.5rem!important}.mt-n2,.my-n2{margin-top:-.5rem!important}.mr-n2,.mx-n2{margin-right:-.5rem!important}.mb-n2,.my-n2{margin-bottom:-.5rem!important}.ml-n2,.mx-n2{margin-left:-.5rem!important}.m-n3{margin:-1rem!important}.mt-n3,.my-n3{margin-top:-1rem!important}.mr-n3,.mx-n3{margin-right:-1rem!important}.mb-n3,.my-n3{margin-bottom:-1rem!important}.ml-n3,.mx-n3{margin-left:-1rem!important}.m-n4{margin:-1.5rem!important}.mt-n4,.my-n4{margin-top:-1.5rem!important}.mr-n4,.mx-n4{margin-right:-1.5rem!important}.mb-n4,.my-n4{margin-bottom:-1.5rem!important}.ml-n4,.mx-n4{margin-left:-1.5rem!important}.m-n5{margin:-3rem!important}.mt-n5,.my-n5{margin-top:-3rem!important}.mr-n5,.mx-n5{margin-right:-3rem!important}.mb-n5,.my-n5{margin-bottom:-3rem!important}.ml-n5,.mx-n5{margin-left:-3rem!important}.m-auto{margin:auto!important}.mt-auto,.my-auto{margin-top:auto!important}.mr-auto,.mx-auto{margin-right:auto!important}.mb-auto,.my-auto{margin-bottom:auto!important}.ml-auto,.mx-auto{margin-left:auto!important}@media(min-width:576px){.m-sm-0{margin:0!important}.mt-sm-0,.my-sm-0{margin-top:0!important}.mr-sm-0,.mx-sm-0{margin-right:0!important}.mb-sm-0,.my-sm-0{margin-bottom:0!important}.ml-sm-0,.mx-sm-0{margin-left:0!important}.m-sm-1{margin:.25rem!important}.mt-sm-1,.my-sm-1{margin-top:.25rem!important}.mr-sm-1,.mx-sm-1{margin-right:.25rem!important}.mb-sm-1,.my-sm-1{margin-bottom:.25rem!important}.ml-sm-1,.mx-sm-1{margin-left:.25rem!important}.m-sm-2{margin:.5rem!important}.mt-sm-2,.my-sm-2{margin-top:.5rem!important}.mr-sm-2,.mx-sm-2{margin-right:.5rem!important}.mb-sm-2,.my-sm-2{margin-bottom:.5rem!important}.ml-sm-2,.mx-sm-2{margin-left:.5rem!important}.m-sm-3{margin:1rem!important}.mt-sm-3,.my-sm-3{margin-top:1rem!important}.mr-sm-3,.mx-sm-3{margin-right:1rem!important}.mb-sm-3,.my-sm-3{margin-bottom:1rem!important}.ml-sm-3,.mx-sm-3{margin-left:1rem!important}.m-sm-4{margin:1.5rem!important}.mt-sm-4,.my-sm-4{margin-top:1.5rem!important}.mr-sm-4,.mx-sm-4{margin-right:1.5rem!important}.mb-sm-4,.my-sm-4{margin-bottom:1.5rem!important}.ml-sm-4,.mx-sm-4{margin-left:1.5rem!important}.m-sm-5{margin:3rem!important}.mt-sm-5,.my-sm-5{margin-top:3rem!important}.mr-sm-5,.mx-sm-5{margin-right:3rem!important}.mb-sm-5,.my-sm-5{margin-bottom:3rem!important}.ml-sm-5,.mx-sm-5{margin-left:3rem!important}.p-sm-0{padding:0!important}.pt-sm-0,.py-sm-0{padding-top:0!important}.pr-sm-0,.px-sm-0{padding-right:0!important}.pb-sm-0,.py-sm-0{padding-bottom:0!important}.pl-sm-0,.px-sm-0{padding-left:0!important}.p-sm-1{padding:.25rem!important}.pt-sm-1,.py-sm-1{padding-top:.25rem!important}.pr-sm-1,.px-sm-1{padding-right:.25rem!important}.pb-sm-1,.py-sm-1{padding-bottom:.25rem!important}.pl-sm-1,.px-sm-1{padding-left:.25rem!important}.p-sm-2{padding:.5rem!important}.pt-sm-2,.py-sm-2{padding-top:.5rem!important}.pr-sm-2,.px-sm-2{padding-right:.5rem!important}.pb-sm-2,.py-sm-2{padding-bottom:.5rem!important}.pl-sm-2,.px-sm-2{padding-left:.5rem!important}.p-sm-3{padding:1rem!important}.pt-sm-3,.py-sm-3{padding-top:1rem!important}.pr-sm-3,.px-sm-3{padding-right:1rem!important}.pb-sm-3,.py-sm-3{padding-bottom:1rem!important}.pl-sm-3,.px-sm-3{padding-left:1rem!important}.p-sm-4{padding:1.5rem!important}.pt-sm-4,.py-sm-4{padding-top:1.5rem!important}.pr-sm-4,.px-sm-4{padding-right:1.5rem!important}.pb-sm-4,.py-sm-4{padding-bottom:1.5rem!important}.pl-sm-4,.px-sm-4{padding-left:1.5rem!important}.p-sm-5{padding:3rem!important}.pt-sm-5,.py-sm-5{padding-top:3rem!important}.pr-sm-5,.px-sm-5{padding-right:3rem!important}.pb-sm-5,.py-sm-5{padding-bottom:3rem!important}.pl-sm-5,.px-sm-5{padding-left:3rem!important}.m-sm-n1{margin:-.25rem!important}.mt-sm-n1,.my-sm-n1{margin-top:-.25rem!important}.mr-sm-n1,.mx-sm-n1{margin-right:-.25rem!important}.mb-sm-n1,.my-sm-n1{margin-bottom:-.25rem!important}.ml-sm-n1,.mx-sm-n1{margin-left:-.25rem!important}.m-sm-n2{margin:-.5rem!important}.mt-sm-n2,.my-sm-n2{margin-top:-.5rem!important}.mr-sm-n2,.mx-sm-n2{margin-right:-.5rem!important}.mb-sm-n2,.my-sm-n2{margin-bottom:-.5rem!important}.ml-sm-n2,.mx-sm-n2{margin-left:-.5rem!important}.m-sm-n3{margin:-1rem!important}.mt-sm-n3,.my-sm-n3{margin-top:-1rem!important}.mr-sm-n3,.mx-sm-n3{margin-right:-1rem!important}.mb-sm-n3,.my-sm-n3{margin-bottom:-1rem!important}.ml-sm-n3,.mx-sm-n3{margin-left:-1rem!important}.m-sm-n4{margin:-1.5rem!important}.mt-sm-n4,.my-sm-n4{margin-top:-1.5rem!important}.mr-sm-n4,.mx-sm-n4{margin-right:-1.5rem!important}.mb-sm-n4,.my-sm-n4{margin-bottom:-1.5rem!important}.ml-sm-n4,.mx-sm-n4{margin-left:-1.5rem!important}.m-sm-n5{margin:-3rem!important}.mt-sm-n5,.my-sm-n5{margin-top:-3rem!important}.mr-sm-n5,.mx-sm-n5{margin-right:-3rem!important}.mb-sm-n5,.my-sm-n5{margin-bottom:-3rem!important}.ml-sm-n5,.mx-sm-n5{margin-left:-3rem!important}.m-sm-auto{margin:auto!important}.mt-sm-auto,.my-sm-auto{margin-top:auto!important}.mr-sm-auto,.mx-sm-auto{margin-right:auto!important}.mb-sm-auto,.my-sm-auto{margin-bottom:auto!important}.ml-sm-auto,.mx-sm-auto{margin-left:auto!important}}@media(min-width:768px){.m-md-0{margin:0!important}.mt-md-0,.my-md-0{margin-top:0!important}.mr-md-0,.mx-md-0{margin-right:0!important}.mb-md-0,.my-md-0{margin-bottom:0!important}.ml-md-0,.mx-md-0{margin-left:0!important}.m-md-1{margin:.25rem!important}.mt-md-1,.my-md-1{margin-top:.25rem!important}.mr-md-1,.mx-md-1{margin-right:.25rem!important}.mb-md-1,.my-md-1{margin-bottom:.25rem!important}.ml-md-1,.mx-md-1{margin-left:.25rem!important}.m-md-2{margin:.5rem!important}.mt-md-2,.my-md-2{margin-top:.5rem!important}.mr-md-2,.mx-md-2{margin-right:.5rem!important}.mb-md-2,.my-md-2{margin-bottom:.5rem!important}.ml-md-2,.mx-md-2{margin-left:.5rem!important}.m-md-3{margin:1rem!important}.mt-md-3,.my-md-3{margin-top:1rem!important}.mr-md-3,.mx-md-3{margin-right:1rem!important}.mb-md-3,.my-md-3{margin-bottom:1rem!important}.ml-md-3,.mx-md-3{margin-left:1rem!important}.m-md-4{margin:1.5rem!important}.mt-md-4,.my-md-4{margin-top:1.5rem!important}.mr-md-4,.mx-md-4{margin-right:1.5rem!important}.mb-md-4,.my-md-4{margin-bottom:1.5rem!important}.ml-md-4,.mx-md-4{margin-left:1.5rem!important}.m-md-5{margin:3rem!important}.mt-md-5,.my-md-5{margin-top:3rem!important}.mr-md-5,.mx-md-5{margin-right:3rem!important}.mb-md-5,.my-md-5{margin-bottom:3rem!important}.ml-md-5,.mx-md-5{margin-left:3rem!important}.p-md-0{padding:0!important}.pt-md-0,.py-md-0{padding-top:0!important}.pr-md-0,.px-md-0{padding-right:0!important}.pb-md-0,.py-md-0{padding-bottom:0!important}.pl-md-0,.px-md-0{padding-left:0!important}.p-md-1{padding:.25rem!important}.pt-md-1,.py-md-1{padding-top:.25rem!important}.pr-md-1,.px-md-1{padding-right:.25rem!important}.pb-md-1,.py-md-1{padding-bottom:.25rem!important}.pl-md-1,.px-md-1{padding-left:.25rem!important}.p-md-2{padding:.5rem!important}.pt-md-2,.py-md-2{padding-top:.5rem!important}.pr-md-2,.px-md-2{padding-right:.5rem!important}.pb-md-2,.py-md-2{padding-bottom:.5rem!important}.pl-md-2,.px-md-2{padding-left:.5rem!important}.p-md-3{padding:1rem!important}.pt-md-3,.py-md-3{padding-top:1rem!important}.pr-md-3,.px-md-3{padding-right:1rem!important}.pb-md-3,.py-md-3{padding-bottom:1rem!important}.pl-md-3,.px-md-3{padding-left:1rem!important}.p-md-4{padding:1.5rem!important}.pt-md-4,.py-md-4{padding-top:1.5rem!important}.pr-md-4,.px-md-4{padding-right:1.5rem!important}.pb-md-4,.py-md-4{padding-bottom:1.5rem!important}.pl-md-4,.px-md-4{padding-left:1.5rem!important}.p-md-5{padding:3rem!important}.pt-md-5,.py-md-5{padding-top:3rem!important}.pr-md-5,.px-md-5{padding-right:3rem!important}.pb-md-5,.py-md-5{padding-bottom:3rem!important}.pl-md-5,.px-md-5{padding-left:3rem!important}.m-md-n1{margin:-.25rem!important}.mt-md-n1,.my-md-n1{margin-top:-.25rem!important}.mr-md-n1,.mx-md-n1{margin-right:-.25rem!important}.mb-md-n1,.my-md-n1{margin-bottom:-.25rem!important}.ml-md-n1,.mx-md-n1{margin-left:-.25rem!important}.m-md-n2{margin:-.5rem!important}.mt-md-n2,.my-md-n2{margin-top:-.5rem!important}.mr-md-n2,.mx-md-n2{margin-right:-.5rem!important}.mb-md-n2,.my-md-n2{margin-bottom:-.5rem!important}.ml-md-n2,.mx-md-n2{margin-left:-.5rem!important}.m-md-n3{margin:-1rem!important}.mt-md-n3,.my-md-n3{margin-top:-1rem!important}.mr-md-n3,.mx-md-n3{margin-right:-1rem!important}.mb-md-n3,.my-md-n3{margin-bottom:-1rem!important}.ml-md-n3,.mx-md-n3{margin-left:-1rem!important}.m-md-n4{margin:-1.5rem!important}.mt-md-n4,.my-md-n4{margin-top:-1.5rem!important}.mr-md-n4,.mx-md-n4{margin-right:-1.5rem!important}.mb-md-n4,.my-md-n4{margin-bottom:-1.5rem!important}.ml-md-n4,.mx-md-n4{margin-left:-1.5rem!important}.m-md-n5{margin:-3rem!important}.mt-md-n5,.my-md-n5{margin-top:-3rem!important}.mr-md-n5,.mx-md-n5{margin-right:-3rem!important}.mb-md-n5,.my-md-n5{margin-bottom:-3rem!important}.ml-md-n5,.mx-md-n5{margin-left:-3rem!important}.m-md-auto{margin:auto!important}.mt-md-auto,.my-md-auto{margin-top:auto!important}.mr-md-auto,.mx-md-auto{margin-right:auto!important}.mb-md-auto,.my-md-auto{margin-bottom:auto!important}.ml-md-auto,.mx-md-auto{margin-left:auto!important}}@media(min-width:992px){.m-lg-0{margin:0!important}.mt-lg-0,.my-lg-0{margin-top:0!important}.mr-lg-0,.mx-lg-0{margin-right:0!important}.mb-lg-0,.my-lg-0{margin-bottom:0!important}.ml-lg-0,.mx-lg-0{margin-left:0!important}.m-lg-1{margin:.25rem!important}.mt-lg-1,.my-lg-1{margin-top:.25rem!important}.mr-lg-1,.mx-lg-1{margin-right:.25rem!important}.mb-lg-1,.my-lg-1{margin-bottom:.25rem!important}.ml-lg-1,.mx-lg-1{margin-left:.25rem!important}.m-lg-2{margin:.5rem!important}.mt-lg-2,.my-lg-2{margin-top:.5rem!important}.mr-lg-2,.mx-lg-2{margin-right:.5rem!important}.mb-lg-2,.my-lg-2{margin-bottom:.5rem!important}.ml-lg-2,.mx-lg-2{margin-left:.5rem!important}.m-lg-3{margin:1rem!important}.mt-lg-3,.my-lg-3{margin-top:1rem!important}.mr-lg-3,.mx-lg-3{margin-right:1rem!important}.mb-lg-3,.my-lg-3{margin-bottom:1rem!important}.ml-lg-3,.mx-lg-3{margin-left:1rem!important}.m-lg-4{margin:1.5rem!important}.mt-lg-4,.my-lg-4{margin-top:1.5rem!important}.mr-lg-4,.mx-lg-4{margin-right:1.5rem!important}.mb-lg-4,.my-lg-4{margin-bottom:1.5rem!important}.ml-lg-4,.mx-lg-4{margin-left:1.5rem!important}.m-lg-5{margin:3rem!important}.mt-lg-5,.my-lg-5{margin-top:3rem!important}.mr-lg-5,.mx-lg-5{margin-right:3rem!important}.mb-lg-5,.my-lg-5{margin-bottom:3rem!important}.ml-lg-5,.mx-lg-5{margin-left:3rem!important}.p-lg-0{padding:0!important}.pt-lg-0,.py-lg-0{padding-top:0!important}.pr-lg-0,.px-lg-0{padding-right:0!important}.pb-lg-0,.py-lg-0{padding-bottom:0!important}.pl-lg-0,.px-lg-0{padding-left:0!important}.p-lg-1{padding:.25rem!important}.pt-lg-1,.py-lg-1{padding-top:.25rem!important}.pr-lg-1,.px-lg-1{padding-right:.25rem!important}.pb-lg-1,.py-lg-1{padding-bottom:.25rem!important}.pl-lg-1,.px-lg-1{padding-left:.25rem!important}.p-lg-2{padding:.5rem!important}.pt-lg-2,.py-lg-2{padding-top:.5rem!important}.pr-lg-2,.px-lg-2{padding-right:.5rem!important}.pb-lg-2,.py-lg-2{padding-bottom:.5rem!important}.pl-lg-2,.px-lg-2{padding-left:.5rem!important}.p-lg-3{padding:1rem!important}.pt-lg-3,.py-lg-3{padding-top:1rem!important}.pr-lg-3,.px-lg-3{padding-right:1rem!important}.pb-lg-3,.py-lg-3{padding-bottom:1rem!important}.pl-lg-3,.px-lg-3{padding-left:1rem!important}.p-lg-4{padding:1.5rem!important}.pt-lg-4,.py-lg-4{padding-top:1.5rem!important}.pr-lg-4,.px-lg-4{padding-right:1.5rem!important}.pb-lg-4,.py-lg-4{padding-bottom:1.5rem!important}.pl-lg-4,.px-lg-4{padding-left:1.5rem!important}.p-lg-5{padding:3rem!important}.pt-lg-5,.py-lg-5{padding-top:3rem!important}.pr-lg-5,.px-lg-5{padding-right:3rem!important}.pb-lg-5,.py-lg-5{padding-bottom:3rem!important}.pl-lg-5,.px-lg-5{padding-left:3rem!important}.m-lg-n1{margin:-.25rem!important}.mt-lg-n1,.my-lg-n1{margin-top:-.25rem!important}.mr-lg-n1,.mx-lg-n1{margin-right:-.25rem!important}.mb-lg-n1,.my-lg-n1{margin-bottom:-.25rem!important}.ml-lg-n1,.mx-lg-n1{margin-left:-.25rem!important}.m-lg-n2{margin:-.5rem!important}.mt-lg-n2,.my-lg-n2{margin-top:-.5rem!important}.mr-lg-n2,.mx-lg-n2{margin-right:-.5rem!important}.mb-lg-n2,.my-lg-n2{margin-bottom:-.5rem!important}.ml-lg-n2,.mx-lg-n2{margin-left:-.5rem!important}.m-lg-n3{margin:-1rem!important}.mt-lg-n3,.my-lg-n3{margin-top:-1rem!important}.mr-lg-n3,.mx-lg-n3{margin-right:-1rem!important}.mb-lg-n3,.my-lg-n3{margin-bottom:-1rem!important}.ml-lg-n3,.mx-lg-n3{margin-left:-1rem!important}.m-lg-n4{margin:-1.5rem!important}.mt-lg-n4,.my-lg-n4{margin-top:-1.5rem!important}.mr-lg-n4,.mx-lg-n4{margin-right:-1.5rem!important}.mb-lg-n4,.my-lg-n4{margin-bottom:-1.5rem!important}.ml-lg-n4,.mx-lg-n4{margin-left:-1.5rem!important}.m-lg-n5{margin:-3rem!important}.mt-lg-n5,.my-lg-n5{margin-top:-3rem!important}.mr-lg-n5,.mx-lg-n5{margin-right:-3rem!important}.mb-lg-n5,.my-lg-n5{margin-bottom:-3rem!important}.ml-lg-n5,.mx-lg-n5{margin-left:-3rem!important}.m-lg-auto{margin:auto!important}.mt-lg-auto,.my-lg-auto{margin-top:auto!important}.mr-lg-auto,.mx-lg-auto{margin-right:auto!important}.mb-lg-auto,.my-lg-auto{margin-bottom:auto!important}.ml-lg-auto,.mx-lg-auto{margin-left:auto!important}}@media(min-width:1200px){.m-xl-0{margin:0!important}.mt-xl-0,.my-xl-0{margin-top:0!important}.mr-xl-0,.mx-xl-0{margin-right:0!important}.mb-xl-0,.my-xl-0{margin-bottom:0!important}.ml-xl-0,.mx-xl-0{margin-left:0!important}.m-xl-1{margin:.25rem!important}.mt-xl-1,.my-xl-1{margin-top:.25rem!important}.mr-xl-1,.mx-xl-1{margin-right:.25rem!important}.mb-xl-1,.my-xl-1{margin-bottom:.25rem!important}.ml-xl-1,.mx-xl-1{margin-left:.25rem!important}.m-xl-2{margin:.5rem!important}.mt-xl-2,.my-xl-2{margin-top:.5rem!important}.mr-xl-2,.mx-xl-2{margin-right:.5rem!important}.mb-xl-2,.my-xl-2{margin-bottom:.5rem!important}.ml-xl-2,.mx-xl-2{margin-left:.5rem!important}.m-xl-3{margin:1rem!important}.mt-xl-3,.my-xl-3{margin-top:1rem!important}.mr-xl-3,.mx-xl-3{margin-right:1rem!important}.mb-xl-3,.my-xl-3{margin-bottom:1rem!important}.ml-xl-3,.mx-xl-3{margin-left:1rem!important}.m-xl-4{margin:1.5rem!important}.mt-xl-4,.my-xl-4{margin-top:1.5rem!important}.mr-xl-4,.mx-xl-4{margin-right:1.5rem!important}.mb-xl-4,.my-xl-4{margin-bottom:1.5rem!important}.ml-xl-4,.mx-xl-4{margin-left:1.5rem!important}.m-xl-5{margin:3rem!important}.mt-xl-5,.my-xl-5{margin-top:3rem!important}.mr-xl-5,.mx-xl-5{margin-right:3rem!important}.mb-xl-5,.my-xl-5{margin-bottom:3rem!important}.ml-xl-5,.mx-xl-5{margin-left:3rem!important}.p-xl-0{padding:0!important}.pt-xl-0,.py-xl-0{padding-top:0!important}.pr-xl-0,.px-xl-0{padding-right:0!important}.pb-xl-0,.py-xl-0{padding-bottom:0!important}.pl-xl-0,.px-xl-0{padding-left:0!important}.p-xl-1{padding:.25rem!important}.pt-xl-1,.py-xl-1{padding-top:.25rem!important}.pr-xl-1,.px-xl-1{padding-right:.25rem!important}.pb-xl-1,.py-xl-1{padding-bottom:.25rem!important}.pl-xl-1,.px-xl-1{padding-left:.25rem!important}.p-xl-2{padding:.5rem!important}.pt-xl-2,.py-xl-2{padding-top:.5rem!important}.pr-xl-2,.px-xl-2{padding-right:.5rem!important}.pb-xl-2,.py-xl-2{padding-bottom:.5rem!important}.pl-xl-2,.px-xl-2{padding-left:.5rem!important}.p-xl-3{padding:1rem!important}.pt-xl-3,.py-xl-3{padding-top:1rem!important}.pr-xl-3,.px-xl-3{padding-right:1rem!important}.pb-xl-3,.py-xl-3{padding-bottom:1rem!important}.pl-xl-3,.px-xl-3{padding-left:1rem!important}.p-xl-4{padding:1.5rem!important}.pt-xl-4,.py-xl-4{padding-top:1.5rem!important}.pr-xl-4,.px-xl-4{padding-right:1.5rem!important}.pb-xl-4,.py-xl-4{padding-bottom:1.5rem!important}.pl-xl-4,.px-xl-4{padding-left:1.5rem!important}.p-xl-5{padding:3rem!important}.pt-xl-5,.py-xl-5{padding-top:3rem!important}.pr-xl-5,.px-xl-5{padding-right:3rem!important}.pb-xl-5,.py-xl-5{padding-bottom:3rem!important}.pl-xl-5,.px-xl-5{padding-left:3rem!important}.m-xl-n1{margin:-.25rem!important}.mt-xl-n1,.my-xl-n1{margin-top:-.25rem!important}.mr-xl-n1,.mx-xl-n1{margin-right:-.25rem!important}.mb-xl-n1,.my-xl-n1{margin-bottom:-.25rem!important}.ml-xl-n1,.mx-xl-n1{margin-left:-.25rem!important}.m-xl-n2{margin:-.5rem!important}.mt-xl-n2,.my-xl-n2{margin-top:-.5rem!important}.mr-xl-n2,.mx-xl-n2{margin-right:-.5rem!important}.mb-xl-n2,.my-xl-n2{margin-bottom:-.5rem!important}.ml-xl-n2,.mx-xl-n2{margin-left:-.5rem!important}.m-xl-n3{margin:-1rem!important}.mt-xl-n3,.my-xl-n3{margin-top:-1rem!important}.mr-xl-n3,.mx-xl-n3{margin-right:-1rem!important}.mb-xl-n3,.my-xl-n3{margin-bottom:-1rem!important}.ml-xl-n3,.mx-xl-n3{margin-left:-1rem!important}.m-xl-n4{margin:-1.5rem!important}.mt-xl-n4,.my-xl-n4{margin-top:-1.5rem!important}.mr-xl-n4,.mx-xl-n4{margin-right:-1.5rem!important}.mb-xl-n4,.my-xl-n4{margin-bottom:-1.5rem!important}.ml-xl-n4,.mx-xl-n4{margin-left:-1.5rem!important}.m-xl-n5{margin:-3rem!important}.mt-xl-n5,.my-xl-n5{margin-top:-3rem!important}.mr-xl-n5,.mx-xl-n5{margin-right:-3rem!important}.mb-xl-n5,.my-xl-n5{margin-bottom:-3rem!important}.ml-xl-n5,.mx-xl-n5{margin-left:-3rem!important}.m-xl-auto{margin:auto!important}.mt-xl-auto,.my-xl-auto{margin-top:auto!important}.mr-xl-auto,.mx-xl-auto{margin-right:auto!important}.mb-xl-auto,.my-xl-auto{margin-bottom:auto!important}.ml-xl-auto,.mx-xl-auto{margin-left:auto!important}}.stretched-link::after{position:absolute;top:0;right:0;bottom:0;left:0;z-index:1;pointer-events:auto;content:"";background-color:transparent}.text-monospace{font-family:SFMono-Regular,Menlo,Monaco,Consolas,liberation mono,courier new,monospace!important}.text-justify{text-align:justify!important}.text-wrap{white-space:normal!important}.text-nowrap{white-space:nowrap!important}.text-truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.text-left{text-align:left!important}.text-right{text-align:right!important}.text-center{text-align:center!important}@media(min-width:576px){.text-sm-left{text-align:left!important}.text-sm-right{text-align:right!important}.text-sm-center{text-align:center!important}}@media(min-width:768px){.text-md-left{text-align:left!important}.text-md-right{text-align:right!important}.text-md-center{text-align:center!important}}@media(min-width:992px){.text-lg-left{text-align:left!important}.text-lg-right{text-align:right!important}.text-lg-center{text-align:center!important}}@media(min-width:1200px){.text-xl-left{text-align:left!important}.text-xl-right{text-align:right!important}.text-xl-center{text-align:center!important}}.text-lowercase{text-transform:lowercase!important}.text-uppercase{text-transform:uppercase!important}.text-capitalize{text-transform:capitalize!important}.font-weight-light{font-weight:300!important}.font-weight-lighter{font-weight:lighter!important}.font-weight-normal{font-weight:400!important}.font-weight-bold{font-weight:700!important}.font-weight-bolder{font-weight:bolder!important}.font-italic{font-style:italic!important}.text-white{color:#fff!important}.text-primary{color:#30638e!important}a.text-primary:hover,a.text-primary:focus{color:#1d3b55!important}.text-secondary{color:#ffa630!important}a.text-secondary:hover,a.text-secondary:focus{color:#e38100!important}.text-success{color:#3772ff!important}a.text-success:hover,a.text-success:focus{color:#0045ea!important}.text-info{color:#c0e0de!important}a.text-info:hover,a.text-info:focus{color:#8dc7c3!important}.text-warning{color:#ed6a5a!important}a.text-warning:hover,a.text-warning:focus{color:#e22f19!important}.text-danger{color:#ed6a5a!important}a.text-danger:hover,a.text-danger:focus{color:#e22f19!important}.text-light{color:#d3f3ee!important}a.text-light:hover,a.text-light:focus{color:#97e3d7!important}.text-dark{color:#403f4c!important}a.text-dark:hover,a.text-dark:focus{color:#1d1c22!important}.text-body{color:#222!important}.text-muted{color:#797676!important}.text-black-50{color:rgba(0,0,0,.5)!important}.text-white-50{color:rgba(255,255,255,.5)!important}.text-hide{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.text-decoration-none{text-decoration:none!important}.text-break{word-break:break-word!important;word-wrap:break-word!important}.text-reset{color:inherit!important}.visible{visibility:visible!important}.invisible{visibility:hidden!important}@media print{*,*::before,*::after{text-shadow:none!important;box-shadow:none!important}a:not(.btn){text-decoration:underline}abbr[title]::after{content:" (" attr(title)")"}pre{white-space:pre-wrap!important}pre,blockquote{border:1px solid #adb5bd;page-break-inside:avoid}tr,img{page-break-inside:avoid}p,h2,h3{orphans:3;widows:3}h2,h3{page-break-after:avoid}@page{size:a3}body{min-width:992px!important}.container{min-width:992px!important}.navbar{display:none}.badge{border:1px solid #000}.table,.td-content>table,.td-box .row.section>table{border-collapse:collapse!important}.table td,.td-content>table td,.td-box .row.section>table td,.table th,.td-content>table th,.td-box .row.section>table th{background-color:#fff!important}.table-bordered th,.table-bordered td{border:1px solid #dee2e6!important}.table-dark{color:inherit}.table-dark th,.table-dark td,.table-dark thead th,.table-dark tbody+tbody{border-color:#dee2e6}.table .thead-dark th,.td-content>table .thead-dark th,.td-box .row.section>table .thead-dark th{color:inherit;border-color:#dee2e6}}/*!* Font Awesome Free 5.15.4 by @fontawesome - https://fontawesome.com +* License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)*/.fa,.fas,.far,.fal,.fad,.fab{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;display:inline-block;font-style:normal;font-variant:normal;text-rendering:auto;line-height:1}.fa-lg{font-size:1.33333333em;line-height:.75em;vertical-align:-.0667em}.fa-xs{font-size:.75em}.fa-sm{font-size:.875em}.fa-1x{font-size:1em}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-6x{font-size:6em}.fa-7x{font-size:7em}.fa-8x{font-size:8em}.fa-9x{font-size:9em}.fa-10x{font-size:10em}.fa-fw{text-align:center;width:1.25em}.fa-ul{list-style-type:none;margin-left:2.5em;padding-left:0}.fa-ul>li{position:relative}.fa-li{left:-2em;position:absolute;text-align:center;width:2em;line-height:inherit}.fa-border{border:solid .08em #eee;border-radius:.1em;padding:.2em .25em .15em}.fa-pull-left{float:left}.fa-pull-right{float:right}.fa.fa-pull-left,.fas.fa-pull-left,.far.fa-pull-left,.fal.fa-pull-left,.fab.fa-pull-left{margin-right:.3em}.fa.fa-pull-right,.fas.fa-pull-right,.far.fa-pull-right,.fal.fa-pull-right,.fab.fa-pull-right{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s infinite linear;animation:fa-spin 2s infinite linear}.fa-pulse{-webkit-animation:fa-spin 1s infinite steps(8);animation:fa-spin 1s infinite steps(8)}@-webkit-keyframes fa-spin{0%{transform:rotate(0)}100%{transform:rotate(360deg)}}@keyframes fa-spin{0%{transform:rotate(0)}100%{transform:rotate(360deg)}}.fa-rotate-90{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=1)";transform:rotate(90deg)}.fa-rotate-180{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2)";transform:rotate(180deg)}.fa-rotate-270{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=3)";transform:rotate(270deg)}.fa-flip-horizontal{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)";transform:scale(-1,1)}.fa-flip-vertical{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)";transform:scale(1,-1)}.fa-flip-both,.fa-flip-horizontal.fa-flip-vertical{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)";transform:scale(-1,-1)}:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270,:root .fa-flip-horizontal,:root .fa-flip-vertical,:root .fa-flip-both{filter:none}.fa-stack{display:inline-block;height:2em;line-height:2em;position:relative;vertical-align:middle;width:2.5em}.fa-stack-1x,.fa-stack-2x{left:0;position:absolute;text-align:center;width:100%}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-500px:before{content:"\f26e"}.fa-accessible-icon:before{content:"\f368"}.fa-accusoft:before{content:"\f369"}.fa-acquisitions-incorporated:before{content:"\f6af"}.fa-ad:before{content:"\f641"}.fa-address-book:before{content:"\f2b9"}.fa-address-card:before{content:"\f2bb"}.fa-adjust:before{content:"\f042"}.fa-adn:before{content:"\f170"}.fa-adversal:before{content:"\f36a"}.fa-affiliatetheme:before{content:"\f36b"}.fa-air-freshener:before{content:"\f5d0"}.fa-airbnb:before{content:"\f834"}.fa-algolia:before{content:"\f36c"}.fa-align-center:before{content:"\f037"}.fa-align-justify:before{content:"\f039"}.fa-align-left:before{content:"\f036"}.fa-align-right:before{content:"\f038"}.fa-alipay:before{content:"\f642"}.fa-allergies:before{content:"\f461"}.fa-amazon:before{content:"\f270"}.fa-amazon-pay:before{content:"\f42c"}.fa-ambulance:before{content:"\f0f9"}.fa-american-sign-language-interpreting:before{content:"\f2a3"}.fa-amilia:before{content:"\f36d"}.fa-anchor:before{content:"\f13d"}.fa-android:before{content:"\f17b"}.fa-angellist:before{content:"\f209"}.fa-angle-double-down:before{content:"\f103"}.fa-angle-double-left:before{content:"\f100"}.fa-angle-double-right:before{content:"\f101"}.fa-angle-double-up:before{content:"\f102"}.fa-angle-down:before{content:"\f107"}.fa-angle-left:before{content:"\f104"}.fa-angle-right:before{content:"\f105"}.fa-angle-up:before{content:"\f106"}.fa-angry:before{content:"\f556"}.fa-angrycreative:before{content:"\f36e"}.fa-angular:before{content:"\f420"}.fa-ankh:before{content:"\f644"}.fa-app-store:before{content:"\f36f"}.fa-app-store-ios:before{content:"\f370"}.fa-apper:before{content:"\f371"}.fa-apple:before{content:"\f179"}.fa-apple-alt:before{content:"\f5d1"}.fa-apple-pay:before{content:"\f415"}.fa-archive:before{content:"\f187"}.fa-archway:before{content:"\f557"}.fa-arrow-alt-circle-down:before{content:"\f358"}.fa-arrow-alt-circle-left:before{content:"\f359"}.fa-arrow-alt-circle-right:before{content:"\f35a"}.fa-arrow-alt-circle-up:before{content:"\f35b"}.fa-arrow-circle-down:before{content:"\f0ab"}.fa-arrow-circle-left:before{content:"\f0a8"}.fa-arrow-circle-right:before{content:"\f0a9"}.fa-arrow-circle-up:before{content:"\f0aa"}.fa-arrow-down:before{content:"\f063"}.fa-arrow-left:before{content:"\f060"}.fa-arrow-right:before{content:"\f061"}.fa-arrow-up:before{content:"\f062"}.fa-arrows-alt:before{content:"\f0b2"}.fa-arrows-alt-h:before{content:"\f337"}.fa-arrows-alt-v:before{content:"\f338"}.fa-artstation:before{content:"\f77a"}.fa-assistive-listening-systems:before{content:"\f2a2"}.fa-asterisk:before{content:"\f069"}.fa-asymmetrik:before{content:"\f372"}.fa-at:before{content:"\f1fa"}.fa-atlas:before{content:"\f558"}.fa-atlassian:before{content:"\f77b"}.fa-atom:before{content:"\f5d2"}.fa-audible:before{content:"\f373"}.fa-audio-description:before{content:"\f29e"}.fa-autoprefixer:before{content:"\f41c"}.fa-avianex:before{content:"\f374"}.fa-aviato:before{content:"\f421"}.fa-award:before{content:"\f559"}.fa-aws:before{content:"\f375"}.fa-baby:before{content:"\f77c"}.fa-baby-carriage:before{content:"\f77d"}.fa-backspace:before{content:"\f55a"}.fa-backward:before{content:"\f04a"}.fa-bacon:before{content:"\f7e5"}.fa-bacteria:before{content:"\e059"}.fa-bacterium:before{content:"\e05a"}.fa-bahai:before{content:"\f666"}.fa-balance-scale:before{content:"\f24e"}.fa-balance-scale-left:before{content:"\f515"}.fa-balance-scale-right:before{content:"\f516"}.fa-ban:before{content:"\f05e"}.fa-band-aid:before{content:"\f462"}.fa-bandcamp:before{content:"\f2d5"}.fa-barcode:before{content:"\f02a"}.fa-bars:before{content:"\f0c9"}.fa-baseball-ball:before{content:"\f433"}.fa-basketball-ball:before{content:"\f434"}.fa-bath:before{content:"\f2cd"}.fa-battery-empty:before{content:"\f244"}.fa-battery-full:before{content:"\f240"}.fa-battery-half:before{content:"\f242"}.fa-battery-quarter:before{content:"\f243"}.fa-battery-three-quarters:before{content:"\f241"}.fa-battle-net:before{content:"\f835"}.fa-bed:before{content:"\f236"}.fa-beer:before{content:"\f0fc"}.fa-behance:before{content:"\f1b4"}.fa-behance-square:before{content:"\f1b5"}.fa-bell:before{content:"\f0f3"}.fa-bell-slash:before{content:"\f1f6"}.fa-bezier-curve:before{content:"\f55b"}.fa-bible:before{content:"\f647"}.fa-bicycle:before{content:"\f206"}.fa-biking:before{content:"\f84a"}.fa-bimobject:before{content:"\f378"}.fa-binoculars:before{content:"\f1e5"}.fa-biohazard:before{content:"\f780"}.fa-birthday-cake:before{content:"\f1fd"}.fa-bitbucket:before{content:"\f171"}.fa-bitcoin:before{content:"\f379"}.fa-bity:before{content:"\f37a"}.fa-black-tie:before{content:"\f27e"}.fa-blackberry:before{content:"\f37b"}.fa-blender:before{content:"\f517"}.fa-blender-phone:before{content:"\f6b6"}.fa-blind:before{content:"\f29d"}.fa-blog:before{content:"\f781"}.fa-blogger:before{content:"\f37c"}.fa-blogger-b:before{content:"\f37d"}.fa-bluetooth:before{content:"\f293"}.fa-bluetooth-b:before{content:"\f294"}.fa-bold:before{content:"\f032"}.fa-bolt:before{content:"\f0e7"}.fa-bomb:before{content:"\f1e2"}.fa-bone:before{content:"\f5d7"}.fa-bong:before{content:"\f55c"}.fa-book:before{content:"\f02d"}.fa-book-dead:before{content:"\f6b7"}.fa-book-medical:before{content:"\f7e6"}.fa-book-open:before{content:"\f518"}.fa-book-reader:before{content:"\f5da"}.fa-bookmark:before{content:"\f02e"}.fa-bootstrap:before{content:"\f836"}.fa-border-all:before{content:"\f84c"}.fa-border-none:before{content:"\f850"}.fa-border-style:before{content:"\f853"}.fa-bowling-ball:before{content:"\f436"}.fa-box:before{content:"\f466"}.fa-box-open:before{content:"\f49e"}.fa-box-tissue:before{content:"\e05b"}.fa-boxes:before{content:"\f468"}.fa-braille:before{content:"\f2a1"}.fa-brain:before{content:"\f5dc"}.fa-bread-slice:before{content:"\f7ec"}.fa-briefcase:before{content:"\f0b1"}.fa-briefcase-medical:before{content:"\f469"}.fa-broadcast-tower:before{content:"\f519"}.fa-broom:before{content:"\f51a"}.fa-brush:before{content:"\f55d"}.fa-btc:before{content:"\f15a"}.fa-buffer:before{content:"\f837"}.fa-bug:before{content:"\f188"}.fa-building:before{content:"\f1ad"}.fa-bullhorn:before{content:"\f0a1"}.fa-bullseye:before{content:"\f140"}.fa-burn:before{content:"\f46a"}.fa-buromobelexperte:before{content:"\f37f"}.fa-bus:before{content:"\f207"}.fa-bus-alt:before{content:"\f55e"}.fa-business-time:before{content:"\f64a"}.fa-buy-n-large:before{content:"\f8a6"}.fa-buysellads:before{content:"\f20d"}.fa-calculator:before{content:"\f1ec"}.fa-calendar:before{content:"\f133"}.fa-calendar-alt:before{content:"\f073"}.fa-calendar-check:before{content:"\f274"}.fa-calendar-day:before{content:"\f783"}.fa-calendar-minus:before{content:"\f272"}.fa-calendar-plus:before{content:"\f271"}.fa-calendar-times:before{content:"\f273"}.fa-calendar-week:before{content:"\f784"}.fa-camera:before{content:"\f030"}.fa-camera-retro:before{content:"\f083"}.fa-campground:before{content:"\f6bb"}.fa-canadian-maple-leaf:before{content:"\f785"}.fa-candy-cane:before{content:"\f786"}.fa-cannabis:before{content:"\f55f"}.fa-capsules:before{content:"\f46b"}.fa-car:before{content:"\f1b9"}.fa-car-alt:before{content:"\f5de"}.fa-car-battery:before{content:"\f5df"}.fa-car-crash:before{content:"\f5e1"}.fa-car-side:before{content:"\f5e4"}.fa-caravan:before{content:"\f8ff"}.fa-caret-down:before{content:"\f0d7"}.fa-caret-left:before{content:"\f0d9"}.fa-caret-right:before{content:"\f0da"}.fa-caret-square-down:before{content:"\f150"}.fa-caret-square-left:before{content:"\f191"}.fa-caret-square-right:before{content:"\f152"}.fa-caret-square-up:before{content:"\f151"}.fa-caret-up:before{content:"\f0d8"}.fa-carrot:before{content:"\f787"}.fa-cart-arrow-down:before{content:"\f218"}.fa-cart-plus:before{content:"\f217"}.fa-cash-register:before{content:"\f788"}.fa-cat:before{content:"\f6be"}.fa-cc-amazon-pay:before{content:"\f42d"}.fa-cc-amex:before{content:"\f1f3"}.fa-cc-apple-pay:before{content:"\f416"}.fa-cc-diners-club:before{content:"\f24c"}.fa-cc-discover:before{content:"\f1f2"}.fa-cc-jcb:before{content:"\f24b"}.fa-cc-mastercard:before{content:"\f1f1"}.fa-cc-paypal:before{content:"\f1f4"}.fa-cc-stripe:before{content:"\f1f5"}.fa-cc-visa:before{content:"\f1f0"}.fa-centercode:before{content:"\f380"}.fa-centos:before{content:"\f789"}.fa-certificate:before{content:"\f0a3"}.fa-chair:before{content:"\f6c0"}.fa-chalkboard:before{content:"\f51b"}.fa-chalkboard-teacher:before{content:"\f51c"}.fa-charging-station:before{content:"\f5e7"}.fa-chart-area:before{content:"\f1fe"}.fa-chart-bar:before{content:"\f080"}.fa-chart-line:before{content:"\f201"}.fa-chart-pie:before{content:"\f200"}.fa-check:before{content:"\f00c"}.fa-check-circle:before{content:"\f058"}.fa-check-double:before{content:"\f560"}.fa-check-square:before{content:"\f14a"}.fa-cheese:before{content:"\f7ef"}.fa-chess:before{content:"\f439"}.fa-chess-bishop:before{content:"\f43a"}.fa-chess-board:before{content:"\f43c"}.fa-chess-king:before{content:"\f43f"}.fa-chess-knight:before{content:"\f441"}.fa-chess-pawn:before{content:"\f443"}.fa-chess-queen:before{content:"\f445"}.fa-chess-rook:before{content:"\f447"}.fa-chevron-circle-down:before{content:"\f13a"}.fa-chevron-circle-left:before{content:"\f137"}.fa-chevron-circle-right:before{content:"\f138"}.fa-chevron-circle-up:before{content:"\f139"}.fa-chevron-down:before{content:"\f078"}.fa-chevron-left:before{content:"\f053"}.fa-chevron-right:before{content:"\f054"}.fa-chevron-up:before{content:"\f077"}.fa-child:before{content:"\f1ae"}.fa-chrome:before{content:"\f268"}.fa-chromecast:before{content:"\f838"}.fa-church:before{content:"\f51d"}.fa-circle:before{content:"\f111"}.fa-circle-notch:before{content:"\f1ce"}.fa-city:before{content:"\f64f"}.fa-clinic-medical:before{content:"\f7f2"}.fa-clipboard:before{content:"\f328"}.fa-clipboard-check:before{content:"\f46c"}.fa-clipboard-list:before{content:"\f46d"}.fa-clock:before{content:"\f017"}.fa-clone:before{content:"\f24d"}.fa-closed-captioning:before{content:"\f20a"}.fa-cloud:before{content:"\f0c2"}.fa-cloud-download-alt:before{content:"\f381"}.fa-cloud-meatball:before{content:"\f73b"}.fa-cloud-moon:before{content:"\f6c3"}.fa-cloud-moon-rain:before{content:"\f73c"}.fa-cloud-rain:before{content:"\f73d"}.fa-cloud-showers-heavy:before{content:"\f740"}.fa-cloud-sun:before{content:"\f6c4"}.fa-cloud-sun-rain:before{content:"\f743"}.fa-cloud-upload-alt:before{content:"\f382"}.fa-cloudflare:before{content:"\e07d"}.fa-cloudscale:before{content:"\f383"}.fa-cloudsmith:before{content:"\f384"}.fa-cloudversify:before{content:"\f385"}.fa-cocktail:before{content:"\f561"}.fa-code:before{content:"\f121"}.fa-code-branch:before{content:"\f126"}.fa-codepen:before{content:"\f1cb"}.fa-codiepie:before{content:"\f284"}.fa-coffee:before{content:"\f0f4"}.fa-cog:before{content:"\f013"}.fa-cogs:before{content:"\f085"}.fa-coins:before{content:"\f51e"}.fa-columns:before{content:"\f0db"}.fa-comment:before{content:"\f075"}.fa-comment-alt:before{content:"\f27a"}.fa-comment-dollar:before{content:"\f651"}.fa-comment-dots:before{content:"\f4ad"}.fa-comment-medical:before{content:"\f7f5"}.fa-comment-slash:before{content:"\f4b3"}.fa-comments:before{content:"\f086"}.fa-comments-dollar:before{content:"\f653"}.fa-compact-disc:before{content:"\f51f"}.fa-compass:before{content:"\f14e"}.fa-compress:before{content:"\f066"}.fa-compress-alt:before{content:"\f422"}.fa-compress-arrows-alt:before{content:"\f78c"}.fa-concierge-bell:before{content:"\f562"}.fa-confluence:before{content:"\f78d"}.fa-connectdevelop:before{content:"\f20e"}.fa-contao:before{content:"\f26d"}.fa-cookie:before{content:"\f563"}.fa-cookie-bite:before{content:"\f564"}.fa-copy:before{content:"\f0c5"}.fa-copyright:before{content:"\f1f9"}.fa-cotton-bureau:before{content:"\f89e"}.fa-couch:before{content:"\f4b8"}.fa-cpanel:before{content:"\f388"}.fa-creative-commons:before{content:"\f25e"}.fa-creative-commons-by:before{content:"\f4e7"}.fa-creative-commons-nc:before{content:"\f4e8"}.fa-creative-commons-nc-eu:before{content:"\f4e9"}.fa-creative-commons-nc-jp:before{content:"\f4ea"}.fa-creative-commons-nd:before{content:"\f4eb"}.fa-creative-commons-pd:before{content:"\f4ec"}.fa-creative-commons-pd-alt:before{content:"\f4ed"}.fa-creative-commons-remix:before{content:"\f4ee"}.fa-creative-commons-sa:before{content:"\f4ef"}.fa-creative-commons-sampling:before{content:"\f4f0"}.fa-creative-commons-sampling-plus:before{content:"\f4f1"}.fa-creative-commons-share:before{content:"\f4f2"}.fa-creative-commons-zero:before{content:"\f4f3"}.fa-credit-card:before{content:"\f09d"}.fa-critical-role:before{content:"\f6c9"}.fa-crop:before{content:"\f125"}.fa-crop-alt:before{content:"\f565"}.fa-cross:before{content:"\f654"}.fa-crosshairs:before{content:"\f05b"}.fa-crow:before{content:"\f520"}.fa-crown:before{content:"\f521"}.fa-crutch:before{content:"\f7f7"}.fa-css3:before{content:"\f13c"}.fa-css3-alt:before{content:"\f38b"}.fa-cube:before{content:"\f1b2"}.fa-cubes:before{content:"\f1b3"}.fa-cut:before{content:"\f0c4"}.fa-cuttlefish:before{content:"\f38c"}.fa-d-and-d:before{content:"\f38d"}.fa-d-and-d-beyond:before{content:"\f6ca"}.fa-dailymotion:before{content:"\e052"}.fa-dashcube:before{content:"\f210"}.fa-database:before{content:"\f1c0"}.fa-deaf:before{content:"\f2a4"}.fa-deezer:before{content:"\e077"}.fa-delicious:before{content:"\f1a5"}.fa-democrat:before{content:"\f747"}.fa-deploydog:before{content:"\f38e"}.fa-deskpro:before{content:"\f38f"}.fa-desktop:before{content:"\f108"}.fa-dev:before{content:"\f6cc"}.fa-deviantart:before{content:"\f1bd"}.fa-dharmachakra:before{content:"\f655"}.fa-dhl:before{content:"\f790"}.fa-diagnoses:before{content:"\f470"}.fa-diaspora:before{content:"\f791"}.fa-dice:before{content:"\f522"}.fa-dice-d20:before{content:"\f6cf"}.fa-dice-d6:before{content:"\f6d1"}.fa-dice-five:before{content:"\f523"}.fa-dice-four:before{content:"\f524"}.fa-dice-one:before{content:"\f525"}.fa-dice-six:before{content:"\f526"}.fa-dice-three:before{content:"\f527"}.fa-dice-two:before{content:"\f528"}.fa-digg:before{content:"\f1a6"}.fa-digital-ocean:before{content:"\f391"}.fa-digital-tachograph:before{content:"\f566"}.fa-directions:before{content:"\f5eb"}.fa-discord:before{content:"\f392"}.fa-discourse:before{content:"\f393"}.fa-disease:before{content:"\f7fa"}.fa-divide:before{content:"\f529"}.fa-dizzy:before{content:"\f567"}.fa-dna:before{content:"\f471"}.fa-dochub:before{content:"\f394"}.fa-docker:before{content:"\f395"}.fa-dog:before{content:"\f6d3"}.fa-dollar-sign:before{content:"\f155"}.fa-dolly:before{content:"\f472"}.fa-dolly-flatbed:before{content:"\f474"}.fa-donate:before{content:"\f4b9"}.fa-door-closed:before{content:"\f52a"}.fa-door-open:before{content:"\f52b"}.fa-dot-circle:before{content:"\f192"}.fa-dove:before{content:"\f4ba"}.fa-download:before{content:"\f019"}.fa-draft2digital:before{content:"\f396"}.fa-drafting-compass:before{content:"\f568"}.fa-dragon:before{content:"\f6d5"}.fa-draw-polygon:before{content:"\f5ee"}.fa-dribbble:before{content:"\f17d"}.fa-dribbble-square:before{content:"\f397"}.fa-dropbox:before{content:"\f16b"}.fa-drum:before{content:"\f569"}.fa-drum-steelpan:before{content:"\f56a"}.fa-drumstick-bite:before{content:"\f6d7"}.fa-drupal:before{content:"\f1a9"}.fa-dumbbell:before{content:"\f44b"}.fa-dumpster:before{content:"\f793"}.fa-dumpster-fire:before{content:"\f794"}.fa-dungeon:before{content:"\f6d9"}.fa-dyalog:before{content:"\f399"}.fa-earlybirds:before{content:"\f39a"}.fa-ebay:before{content:"\f4f4"}.fa-edge:before{content:"\f282"}.fa-edge-legacy:before{content:"\e078"}.fa-edit:before{content:"\f044"}.fa-egg:before{content:"\f7fb"}.fa-eject:before{content:"\f052"}.fa-elementor:before{content:"\f430"}.fa-ellipsis-h:before{content:"\f141"}.fa-ellipsis-v:before{content:"\f142"}.fa-ello:before{content:"\f5f1"}.fa-ember:before{content:"\f423"}.fa-empire:before{content:"\f1d1"}.fa-envelope:before{content:"\f0e0"}.fa-envelope-open:before{content:"\f2b6"}.fa-envelope-open-text:before{content:"\f658"}.fa-envelope-square:before{content:"\f199"}.fa-envira:before{content:"\f299"}.fa-equals:before{content:"\f52c"}.fa-eraser:before{content:"\f12d"}.fa-erlang:before{content:"\f39d"}.fa-ethereum:before{content:"\f42e"}.fa-ethernet:before{content:"\f796"}.fa-etsy:before{content:"\f2d7"}.fa-euro-sign:before{content:"\f153"}.fa-evernote:before{content:"\f839"}.fa-exchange-alt:before{content:"\f362"}.fa-exclamation:before{content:"\f12a"}.fa-exclamation-circle:before{content:"\f06a"}.fa-exclamation-triangle:before{content:"\f071"}.fa-expand:before{content:"\f065"}.fa-expand-alt:before{content:"\f424"}.fa-expand-arrows-alt:before{content:"\f31e"}.fa-expeditedssl:before{content:"\f23e"}.fa-external-link-alt:before{content:"\f35d"}.fa-external-link-square-alt:before{content:"\f360"}.fa-eye:before{content:"\f06e"}.fa-eye-dropper:before{content:"\f1fb"}.fa-eye-slash:before{content:"\f070"}.fa-facebook:before{content:"\f09a"}.fa-facebook-f:before{content:"\f39e"}.fa-facebook-messenger:before{content:"\f39f"}.fa-facebook-square:before{content:"\f082"}.fa-fan:before{content:"\f863"}.fa-fantasy-flight-games:before{content:"\f6dc"}.fa-fast-backward:before{content:"\f049"}.fa-fast-forward:before{content:"\f050"}.fa-faucet:before{content:"\e005"}.fa-fax:before{content:"\f1ac"}.fa-feather:before{content:"\f52d"}.fa-feather-alt:before{content:"\f56b"}.fa-fedex:before{content:"\f797"}.fa-fedora:before{content:"\f798"}.fa-female:before{content:"\f182"}.fa-fighter-jet:before{content:"\f0fb"}.fa-figma:before{content:"\f799"}.fa-file:before{content:"\f15b"}.fa-file-alt:before{content:"\f15c"}.fa-file-archive:before{content:"\f1c6"}.fa-file-audio:before{content:"\f1c7"}.fa-file-code:before{content:"\f1c9"}.fa-file-contract:before{content:"\f56c"}.fa-file-csv:before{content:"\f6dd"}.fa-file-download:before{content:"\f56d"}.fa-file-excel:before{content:"\f1c3"}.fa-file-export:before{content:"\f56e"}.fa-file-image:before{content:"\f1c5"}.fa-file-import:before{content:"\f56f"}.fa-file-invoice:before{content:"\f570"}.fa-file-invoice-dollar:before{content:"\f571"}.fa-file-medical:before{content:"\f477"}.fa-file-medical-alt:before{content:"\f478"}.fa-file-pdf:before{content:"\f1c1"}.fa-file-powerpoint:before{content:"\f1c4"}.fa-file-prescription:before{content:"\f572"}.fa-file-signature:before{content:"\f573"}.fa-file-upload:before{content:"\f574"}.fa-file-video:before{content:"\f1c8"}.fa-file-word:before{content:"\f1c2"}.fa-fill:before{content:"\f575"}.fa-fill-drip:before{content:"\f576"}.fa-film:before{content:"\f008"}.fa-filter:before{content:"\f0b0"}.fa-fingerprint:before{content:"\f577"}.fa-fire:before{content:"\f06d"}.fa-fire-alt:before{content:"\f7e4"}.fa-fire-extinguisher:before{content:"\f134"}.fa-firefox:before{content:"\f269"}.fa-firefox-browser:before{content:"\e007"}.fa-first-aid:before{content:"\f479"}.fa-first-order:before{content:"\f2b0"}.fa-first-order-alt:before{content:"\f50a"}.fa-firstdraft:before{content:"\f3a1"}.fa-fish:before{content:"\f578"}.fa-fist-raised:before{content:"\f6de"}.fa-flag:before{content:"\f024"}.fa-flag-checkered:before{content:"\f11e"}.fa-flag-usa:before{content:"\f74d"}.fa-flask:before{content:"\f0c3"}.fa-flickr:before{content:"\f16e"}.fa-flipboard:before{content:"\f44d"}.fa-flushed:before{content:"\f579"}.fa-fly:before{content:"\f417"}.fa-folder:before{content:"\f07b"}.fa-folder-minus:before{content:"\f65d"}.fa-folder-open:before{content:"\f07c"}.fa-folder-plus:before{content:"\f65e"}.fa-font:before{content:"\f031"}.fa-font-awesome:before{content:"\f2b4"}.fa-font-awesome-alt:before{content:"\f35c"}.fa-font-awesome-flag:before{content:"\f425"}.fa-font-awesome-logo-full:before{content:"\f4e6"}.fa-fonticons:before{content:"\f280"}.fa-fonticons-fi:before{content:"\f3a2"}.fa-football-ball:before{content:"\f44e"}.fa-fort-awesome:before{content:"\f286"}.fa-fort-awesome-alt:before{content:"\f3a3"}.fa-forumbee:before{content:"\f211"}.fa-forward:before{content:"\f04e"}.fa-foursquare:before{content:"\f180"}.fa-free-code-camp:before{content:"\f2c5"}.fa-freebsd:before{content:"\f3a4"}.fa-frog:before{content:"\f52e"}.fa-frown:before{content:"\f119"}.fa-frown-open:before{content:"\f57a"}.fa-fulcrum:before{content:"\f50b"}.fa-funnel-dollar:before{content:"\f662"}.fa-futbol:before{content:"\f1e3"}.fa-galactic-republic:before{content:"\f50c"}.fa-galactic-senate:before{content:"\f50d"}.fa-gamepad:before{content:"\f11b"}.fa-gas-pump:before{content:"\f52f"}.fa-gavel:before{content:"\f0e3"}.fa-gem:before{content:"\f3a5"}.fa-genderless:before{content:"\f22d"}.fa-get-pocket:before{content:"\f265"}.fa-gg:before{content:"\f260"}.fa-gg-circle:before{content:"\f261"}.fa-ghost:before{content:"\f6e2"}.fa-gift:before{content:"\f06b"}.fa-gifts:before{content:"\f79c"}.fa-git:before{content:"\f1d3"}.fa-git-alt:before{content:"\f841"}.fa-git-square:before{content:"\f1d2"}.fa-github:before{content:"\f09b"}.fa-github-alt:before{content:"\f113"}.fa-github-square:before{content:"\f092"}.fa-gitkraken:before{content:"\f3a6"}.fa-gitlab:before{content:"\f296"}.fa-gitter:before{content:"\f426"}.fa-glass-cheers:before{content:"\f79f"}.fa-glass-martini:before{content:"\f000"}.fa-glass-martini-alt:before{content:"\f57b"}.fa-glass-whiskey:before{content:"\f7a0"}.fa-glasses:before{content:"\f530"}.fa-glide:before{content:"\f2a5"}.fa-glide-g:before{content:"\f2a6"}.fa-globe:before{content:"\f0ac"}.fa-globe-africa:before{content:"\f57c"}.fa-globe-americas:before{content:"\f57d"}.fa-globe-asia:before{content:"\f57e"}.fa-globe-europe:before{content:"\f7a2"}.fa-gofore:before{content:"\f3a7"}.fa-golf-ball:before{content:"\f450"}.fa-goodreads:before{content:"\f3a8"}.fa-goodreads-g:before{content:"\f3a9"}.fa-google:before{content:"\f1a0"}.fa-google-drive:before{content:"\f3aa"}.fa-google-pay:before{content:"\e079"}.fa-google-play:before{content:"\f3ab"}.fa-google-plus:before{content:"\f2b3"}.fa-google-plus-g:before{content:"\f0d5"}.fa-google-plus-square:before{content:"\f0d4"}.fa-google-wallet:before{content:"\f1ee"}.fa-gopuram:before{content:"\f664"}.fa-graduation-cap:before{content:"\f19d"}.fa-gratipay:before{content:"\f184"}.fa-grav:before{content:"\f2d6"}.fa-greater-than:before{content:"\f531"}.fa-greater-than-equal:before{content:"\f532"}.fa-grimace:before{content:"\f57f"}.fa-grin:before{content:"\f580"}.fa-grin-alt:before{content:"\f581"}.fa-grin-beam:before{content:"\f582"}.fa-grin-beam-sweat:before{content:"\f583"}.fa-grin-hearts:before{content:"\f584"}.fa-grin-squint:before{content:"\f585"}.fa-grin-squint-tears:before{content:"\f586"}.fa-grin-stars:before{content:"\f587"}.fa-grin-tears:before{content:"\f588"}.fa-grin-tongue:before{content:"\f589"}.fa-grin-tongue-squint:before{content:"\f58a"}.fa-grin-tongue-wink:before{content:"\f58b"}.fa-grin-wink:before{content:"\f58c"}.fa-grip-horizontal:before{content:"\f58d"}.fa-grip-lines:before{content:"\f7a4"}.fa-grip-lines-vertical:before{content:"\f7a5"}.fa-grip-vertical:before{content:"\f58e"}.fa-gripfire:before{content:"\f3ac"}.fa-grunt:before{content:"\f3ad"}.fa-guilded:before{content:"\e07e"}.fa-guitar:before{content:"\f7a6"}.fa-gulp:before{content:"\f3ae"}.fa-h-square:before{content:"\f0fd"}.fa-hacker-news:before{content:"\f1d4"}.fa-hacker-news-square:before{content:"\f3af"}.fa-hackerrank:before{content:"\f5f7"}.fa-hamburger:before{content:"\f805"}.fa-hammer:before{content:"\f6e3"}.fa-hamsa:before{content:"\f665"}.fa-hand-holding:before{content:"\f4bd"}.fa-hand-holding-heart:before{content:"\f4be"}.fa-hand-holding-medical:before{content:"\e05c"}.fa-hand-holding-usd:before{content:"\f4c0"}.fa-hand-holding-water:before{content:"\f4c1"}.fa-hand-lizard:before{content:"\f258"}.fa-hand-middle-finger:before{content:"\f806"}.fa-hand-paper:before{content:"\f256"}.fa-hand-peace:before{content:"\f25b"}.fa-hand-point-down:before{content:"\f0a7"}.fa-hand-point-left:before{content:"\f0a5"}.fa-hand-point-right:before{content:"\f0a4"}.fa-hand-point-up:before{content:"\f0a6"}.fa-hand-pointer:before{content:"\f25a"}.fa-hand-rock:before{content:"\f255"}.fa-hand-scissors:before{content:"\f257"}.fa-hand-sparkles:before{content:"\e05d"}.fa-hand-spock:before{content:"\f259"}.fa-hands:before{content:"\f4c2"}.fa-hands-helping:before{content:"\f4c4"}.fa-hands-wash:before{content:"\e05e"}.fa-handshake:before{content:"\f2b5"}.fa-handshake-alt-slash:before{content:"\e05f"}.fa-handshake-slash:before{content:"\e060"}.fa-hanukiah:before{content:"\f6e6"}.fa-hard-hat:before{content:"\f807"}.fa-hashtag:before{content:"\f292"}.fa-hat-cowboy:before{content:"\f8c0"}.fa-hat-cowboy-side:before{content:"\f8c1"}.fa-hat-wizard:before{content:"\f6e8"}.fa-hdd:before{content:"\f0a0"}.fa-head-side-cough:before{content:"\e061"}.fa-head-side-cough-slash:before{content:"\e062"}.fa-head-side-mask:before{content:"\e063"}.fa-head-side-virus:before{content:"\e064"}.fa-heading:before{content:"\f1dc"}.fa-headphones:before{content:"\f025"}.fa-headphones-alt:before{content:"\f58f"}.fa-headset:before{content:"\f590"}.fa-heart:before{content:"\f004"}.fa-heart-broken:before{content:"\f7a9"}.fa-heartbeat:before{content:"\f21e"}.fa-helicopter:before{content:"\f533"}.fa-highlighter:before{content:"\f591"}.fa-hiking:before{content:"\f6ec"}.fa-hippo:before{content:"\f6ed"}.fa-hips:before{content:"\f452"}.fa-hire-a-helper:before{content:"\f3b0"}.fa-history:before{content:"\f1da"}.fa-hive:before{content:"\e07f"}.fa-hockey-puck:before{content:"\f453"}.fa-holly-berry:before{content:"\f7aa"}.fa-home:before{content:"\f015"}.fa-hooli:before{content:"\f427"}.fa-hornbill:before{content:"\f592"}.fa-horse:before{content:"\f6f0"}.fa-horse-head:before{content:"\f7ab"}.fa-hospital:before{content:"\f0f8"}.fa-hospital-alt:before{content:"\f47d"}.fa-hospital-symbol:before{content:"\f47e"}.fa-hospital-user:before{content:"\f80d"}.fa-hot-tub:before{content:"\f593"}.fa-hotdog:before{content:"\f80f"}.fa-hotel:before{content:"\f594"}.fa-hotjar:before{content:"\f3b1"}.fa-hourglass:before{content:"\f254"}.fa-hourglass-end:before{content:"\f253"}.fa-hourglass-half:before{content:"\f252"}.fa-hourglass-start:before{content:"\f251"}.fa-house-damage:before{content:"\f6f1"}.fa-house-user:before{content:"\e065"}.fa-houzz:before{content:"\f27c"}.fa-hryvnia:before{content:"\f6f2"}.fa-html5:before{content:"\f13b"}.fa-hubspot:before{content:"\f3b2"}.fa-i-cursor:before{content:"\f246"}.fa-ice-cream:before{content:"\f810"}.fa-icicles:before{content:"\f7ad"}.fa-icons:before{content:"\f86d"}.fa-id-badge:before{content:"\f2c1"}.fa-id-card:before{content:"\f2c2"}.fa-id-card-alt:before{content:"\f47f"}.fa-ideal:before{content:"\e013"}.fa-igloo:before{content:"\f7ae"}.fa-image:before{content:"\f03e"}.fa-images:before{content:"\f302"}.fa-imdb:before{content:"\f2d8"}.fa-inbox:before{content:"\f01c"}.fa-indent:before{content:"\f03c"}.fa-industry:before{content:"\f275"}.fa-infinity:before{content:"\f534"}.fa-info:before{content:"\f129"}.fa-info-circle:before{content:"\f05a"}.fa-innosoft:before{content:"\e080"}.fa-instagram:before{content:"\f16d"}.fa-instagram-square:before{content:"\e055"}.fa-instalod:before{content:"\e081"}.fa-intercom:before{content:"\f7af"}.fa-internet-explorer:before{content:"\f26b"}.fa-invision:before{content:"\f7b0"}.fa-ioxhost:before{content:"\f208"}.fa-italic:before{content:"\f033"}.fa-itch-io:before{content:"\f83a"}.fa-itunes:before{content:"\f3b4"}.fa-itunes-note:before{content:"\f3b5"}.fa-java:before{content:"\f4e4"}.fa-jedi:before{content:"\f669"}.fa-jedi-order:before{content:"\f50e"}.fa-jenkins:before{content:"\f3b6"}.fa-jira:before{content:"\f7b1"}.fa-joget:before{content:"\f3b7"}.fa-joint:before{content:"\f595"}.fa-joomla:before{content:"\f1aa"}.fa-journal-whills:before{content:"\f66a"}.fa-js:before{content:"\f3b8"}.fa-js-square:before{content:"\f3b9"}.fa-jsfiddle:before{content:"\f1cc"}.fa-kaaba:before{content:"\f66b"}.fa-kaggle:before{content:"\f5fa"}.fa-key:before{content:"\f084"}.fa-keybase:before{content:"\f4f5"}.fa-keyboard:before{content:"\f11c"}.fa-keycdn:before{content:"\f3ba"}.fa-khanda:before{content:"\f66d"}.fa-kickstarter:before{content:"\f3bb"}.fa-kickstarter-k:before{content:"\f3bc"}.fa-kiss:before{content:"\f596"}.fa-kiss-beam:before{content:"\f597"}.fa-kiss-wink-heart:before{content:"\f598"}.fa-kiwi-bird:before{content:"\f535"}.fa-korvue:before{content:"\f42f"}.fa-landmark:before{content:"\f66f"}.fa-language:before{content:"\f1ab"}.fa-laptop:before{content:"\f109"}.fa-laptop-code:before{content:"\f5fc"}.fa-laptop-house:before{content:"\e066"}.fa-laptop-medical:before{content:"\f812"}.fa-laravel:before{content:"\f3bd"}.fa-lastfm:before{content:"\f202"}.fa-lastfm-square:before{content:"\f203"}.fa-laugh:before{content:"\f599"}.fa-laugh-beam:before{content:"\f59a"}.fa-laugh-squint:before{content:"\f59b"}.fa-laugh-wink:before{content:"\f59c"}.fa-layer-group:before{content:"\f5fd"}.fa-leaf:before{content:"\f06c"}.fa-leanpub:before{content:"\f212"}.fa-lemon:before{content:"\f094"}.fa-less:before{content:"\f41d"}.fa-less-than:before{content:"\f536"}.fa-less-than-equal:before{content:"\f537"}.fa-level-down-alt:before{content:"\f3be"}.fa-level-up-alt:before{content:"\f3bf"}.fa-life-ring:before{content:"\f1cd"}.fa-lightbulb:before{content:"\f0eb"}.fa-line:before{content:"\f3c0"}.fa-link:before{content:"\f0c1"}.fa-linkedin:before{content:"\f08c"}.fa-linkedin-in:before{content:"\f0e1"}.fa-linode:before{content:"\f2b8"}.fa-linux:before{content:"\f17c"}.fa-lira-sign:before{content:"\f195"}.fa-list:before{content:"\f03a"}.fa-list-alt:before{content:"\f022"}.fa-list-ol:before{content:"\f0cb"}.fa-list-ul:before{content:"\f0ca"}.fa-location-arrow:before{content:"\f124"}.fa-lock:before{content:"\f023"}.fa-lock-open:before{content:"\f3c1"}.fa-long-arrow-alt-down:before{content:"\f309"}.fa-long-arrow-alt-left:before{content:"\f30a"}.fa-long-arrow-alt-right:before{content:"\f30b"}.fa-long-arrow-alt-up:before{content:"\f30c"}.fa-low-vision:before{content:"\f2a8"}.fa-luggage-cart:before{content:"\f59d"}.fa-lungs:before{content:"\f604"}.fa-lungs-virus:before{content:"\e067"}.fa-lyft:before{content:"\f3c3"}.fa-magento:before{content:"\f3c4"}.fa-magic:before{content:"\f0d0"}.fa-magnet:before{content:"\f076"}.fa-mail-bulk:before{content:"\f674"}.fa-mailchimp:before{content:"\f59e"}.fa-male:before{content:"\f183"}.fa-mandalorian:before{content:"\f50f"}.fa-map:before{content:"\f279"}.fa-map-marked:before{content:"\f59f"}.fa-map-marked-alt:before{content:"\f5a0"}.fa-map-marker:before{content:"\f041"}.fa-map-marker-alt:before{content:"\f3c5"}.fa-map-pin:before{content:"\f276"}.fa-map-signs:before{content:"\f277"}.fa-markdown:before{content:"\f60f"}.fa-marker:before{content:"\f5a1"}.fa-mars:before{content:"\f222"}.fa-mars-double:before{content:"\f227"}.fa-mars-stroke:before{content:"\f229"}.fa-mars-stroke-h:before{content:"\f22b"}.fa-mars-stroke-v:before{content:"\f22a"}.fa-mask:before{content:"\f6fa"}.fa-mastodon:before{content:"\f4f6"}.fa-maxcdn:before{content:"\f136"}.fa-mdb:before{content:"\f8ca"}.fa-medal:before{content:"\f5a2"}.fa-medapps:before{content:"\f3c6"}.fa-medium:before{content:"\f23a"}.fa-medium-m:before{content:"\f3c7"}.fa-medkit:before{content:"\f0fa"}.fa-medrt:before{content:"\f3c8"}.fa-meetup:before{content:"\f2e0"}.fa-megaport:before{content:"\f5a3"}.fa-meh:before{content:"\f11a"}.fa-meh-blank:before{content:"\f5a4"}.fa-meh-rolling-eyes:before{content:"\f5a5"}.fa-memory:before{content:"\f538"}.fa-mendeley:before{content:"\f7b3"}.fa-menorah:before{content:"\f676"}.fa-mercury:before{content:"\f223"}.fa-meteor:before{content:"\f753"}.fa-microblog:before{content:"\e01a"}.fa-microchip:before{content:"\f2db"}.fa-microphone:before{content:"\f130"}.fa-microphone-alt:before{content:"\f3c9"}.fa-microphone-alt-slash:before{content:"\f539"}.fa-microphone-slash:before{content:"\f131"}.fa-microscope:before{content:"\f610"}.fa-microsoft:before{content:"\f3ca"}.fa-minus:before{content:"\f068"}.fa-minus-circle:before{content:"\f056"}.fa-minus-square:before{content:"\f146"}.fa-mitten:before{content:"\f7b5"}.fa-mix:before{content:"\f3cb"}.fa-mixcloud:before{content:"\f289"}.fa-mixer:before{content:"\e056"}.fa-mizuni:before{content:"\f3cc"}.fa-mobile:before{content:"\f10b"}.fa-mobile-alt:before{content:"\f3cd"}.fa-modx:before{content:"\f285"}.fa-monero:before{content:"\f3d0"}.fa-money-bill:before{content:"\f0d6"}.fa-money-bill-alt:before{content:"\f3d1"}.fa-money-bill-wave:before{content:"\f53a"}.fa-money-bill-wave-alt:before{content:"\f53b"}.fa-money-check:before{content:"\f53c"}.fa-money-check-alt:before{content:"\f53d"}.fa-monument:before{content:"\f5a6"}.fa-moon:before{content:"\f186"}.fa-mortar-pestle:before{content:"\f5a7"}.fa-mosque:before{content:"\f678"}.fa-motorcycle:before{content:"\f21c"}.fa-mountain:before{content:"\f6fc"}.fa-mouse:before{content:"\f8cc"}.fa-mouse-pointer:before{content:"\f245"}.fa-mug-hot:before{content:"\f7b6"}.fa-music:before{content:"\f001"}.fa-napster:before{content:"\f3d2"}.fa-neos:before{content:"\f612"}.fa-network-wired:before{content:"\f6ff"}.fa-neuter:before{content:"\f22c"}.fa-newspaper:before{content:"\f1ea"}.fa-nimblr:before{content:"\f5a8"}.fa-node:before{content:"\f419"}.fa-node-js:before{content:"\f3d3"}.fa-not-equal:before{content:"\f53e"}.fa-notes-medical:before{content:"\f481"}.fa-npm:before{content:"\f3d4"}.fa-ns8:before{content:"\f3d5"}.fa-nutritionix:before{content:"\f3d6"}.fa-object-group:before{content:"\f247"}.fa-object-ungroup:before{content:"\f248"}.fa-octopus-deploy:before{content:"\e082"}.fa-odnoklassniki:before{content:"\f263"}.fa-odnoklassniki-square:before{content:"\f264"}.fa-oil-can:before{content:"\f613"}.fa-old-republic:before{content:"\f510"}.fa-om:before{content:"\f679"}.fa-opencart:before{content:"\f23d"}.fa-openid:before{content:"\f19b"}.fa-opera:before{content:"\f26a"}.fa-optin-monster:before{content:"\f23c"}.fa-orcid:before{content:"\f8d2"}.fa-osi:before{content:"\f41a"}.fa-otter:before{content:"\f700"}.fa-outdent:before{content:"\f03b"}.fa-page4:before{content:"\f3d7"}.fa-pagelines:before{content:"\f18c"}.fa-pager:before{content:"\f815"}.fa-paint-brush:before{content:"\f1fc"}.fa-paint-roller:before{content:"\f5aa"}.fa-palette:before{content:"\f53f"}.fa-palfed:before{content:"\f3d8"}.fa-pallet:before{content:"\f482"}.fa-paper-plane:before{content:"\f1d8"}.fa-paperclip:before{content:"\f0c6"}.fa-parachute-box:before{content:"\f4cd"}.fa-paragraph:before{content:"\f1dd"}.fa-parking:before{content:"\f540"}.fa-passport:before{content:"\f5ab"}.fa-pastafarianism:before{content:"\f67b"}.fa-paste:before{content:"\f0ea"}.fa-patreon:before{content:"\f3d9"}.fa-pause:before{content:"\f04c"}.fa-pause-circle:before{content:"\f28b"}.fa-paw:before{content:"\f1b0"}.fa-paypal:before{content:"\f1ed"}.fa-peace:before{content:"\f67c"}.fa-pen:before{content:"\f304"}.fa-pen-alt:before{content:"\f305"}.fa-pen-fancy:before{content:"\f5ac"}.fa-pen-nib:before{content:"\f5ad"}.fa-pen-square:before{content:"\f14b"}.fa-pencil-alt:before{content:"\f303"}.fa-pencil-ruler:before{content:"\f5ae"}.fa-penny-arcade:before{content:"\f704"}.fa-people-arrows:before{content:"\e068"}.fa-people-carry:before{content:"\f4ce"}.fa-pepper-hot:before{content:"\f816"}.fa-perbyte:before{content:"\e083"}.fa-percent:before{content:"\f295"}.fa-percentage:before{content:"\f541"}.fa-periscope:before{content:"\f3da"}.fa-person-booth:before{content:"\f756"}.fa-phabricator:before{content:"\f3db"}.fa-phoenix-framework:before{content:"\f3dc"}.fa-phoenix-squadron:before{content:"\f511"}.fa-phone:before{content:"\f095"}.fa-phone-alt:before{content:"\f879"}.fa-phone-slash:before{content:"\f3dd"}.fa-phone-square:before{content:"\f098"}.fa-phone-square-alt:before{content:"\f87b"}.fa-phone-volume:before{content:"\f2a0"}.fa-photo-video:before{content:"\f87c"}.fa-php:before{content:"\f457"}.fa-pied-piper:before{content:"\f2ae"}.fa-pied-piper-alt:before{content:"\f1a8"}.fa-pied-piper-hat:before{content:"\f4e5"}.fa-pied-piper-pp:before{content:"\f1a7"}.fa-pied-piper-square:before{content:"\e01e"}.fa-piggy-bank:before{content:"\f4d3"}.fa-pills:before{content:"\f484"}.fa-pinterest:before{content:"\f0d2"}.fa-pinterest-p:before{content:"\f231"}.fa-pinterest-square:before{content:"\f0d3"}.fa-pizza-slice:before{content:"\f818"}.fa-place-of-worship:before{content:"\f67f"}.fa-plane:before{content:"\f072"}.fa-plane-arrival:before{content:"\f5af"}.fa-plane-departure:before{content:"\f5b0"}.fa-plane-slash:before{content:"\e069"}.fa-play:before{content:"\f04b"}.fa-play-circle:before{content:"\f144"}.fa-playstation:before{content:"\f3df"}.fa-plug:before{content:"\f1e6"}.fa-plus:before{content:"\f067"}.fa-plus-circle:before{content:"\f055"}.fa-plus-square:before{content:"\f0fe"}.fa-podcast:before{content:"\f2ce"}.fa-poll:before{content:"\f681"}.fa-poll-h:before{content:"\f682"}.fa-poo:before{content:"\f2fe"}.fa-poo-storm:before{content:"\f75a"}.fa-poop:before{content:"\f619"}.fa-portrait:before{content:"\f3e0"}.fa-pound-sign:before{content:"\f154"}.fa-power-off:before{content:"\f011"}.fa-pray:before{content:"\f683"}.fa-praying-hands:before{content:"\f684"}.fa-prescription:before{content:"\f5b1"}.fa-prescription-bottle:before{content:"\f485"}.fa-prescription-bottle-alt:before{content:"\f486"}.fa-print:before{content:"\f02f"}.fa-procedures:before{content:"\f487"}.fa-product-hunt:before{content:"\f288"}.fa-project-diagram:before{content:"\f542"}.fa-pump-medical:before{content:"\e06a"}.fa-pump-soap:before{content:"\e06b"}.fa-pushed:before{content:"\f3e1"}.fa-puzzle-piece:before{content:"\f12e"}.fa-python:before{content:"\f3e2"}.fa-qq:before{content:"\f1d6"}.fa-qrcode:before{content:"\f029"}.fa-question:before{content:"\f128"}.fa-question-circle:before{content:"\f059"}.fa-quidditch:before{content:"\f458"}.fa-quinscape:before{content:"\f459"}.fa-quora:before{content:"\f2c4"}.fa-quote-left:before{content:"\f10d"}.fa-quote-right:before{content:"\f10e"}.fa-quran:before{content:"\f687"}.fa-r-project:before{content:"\f4f7"}.fa-radiation:before{content:"\f7b9"}.fa-radiation-alt:before{content:"\f7ba"}.fa-rainbow:before{content:"\f75b"}.fa-random:before{content:"\f074"}.fa-raspberry-pi:before{content:"\f7bb"}.fa-ravelry:before{content:"\f2d9"}.fa-react:before{content:"\f41b"}.fa-reacteurope:before{content:"\f75d"}.fa-readme:before{content:"\f4d5"}.fa-rebel:before{content:"\f1d0"}.fa-receipt:before{content:"\f543"}.fa-record-vinyl:before{content:"\f8d9"}.fa-recycle:before{content:"\f1b8"}.fa-red-river:before{content:"\f3e3"}.fa-reddit:before{content:"\f1a1"}.fa-reddit-alien:before{content:"\f281"}.fa-reddit-square:before{content:"\f1a2"}.fa-redhat:before{content:"\f7bc"}.fa-redo:before{content:"\f01e"}.fa-redo-alt:before{content:"\f2f9"}.fa-registered:before{content:"\f25d"}.fa-remove-format:before{content:"\f87d"}.fa-renren:before{content:"\f18b"}.fa-reply:before{content:"\f3e5"}.fa-reply-all:before{content:"\f122"}.fa-replyd:before{content:"\f3e6"}.fa-republican:before{content:"\f75e"}.fa-researchgate:before{content:"\f4f8"}.fa-resolving:before{content:"\f3e7"}.fa-restroom:before{content:"\f7bd"}.fa-retweet:before{content:"\f079"}.fa-rev:before{content:"\f5b2"}.fa-ribbon:before{content:"\f4d6"}.fa-ring:before{content:"\f70b"}.fa-road:before{content:"\f018"}.fa-robot:before{content:"\f544"}.fa-rocket:before{content:"\f135"}.fa-rocketchat:before{content:"\f3e8"}.fa-rockrms:before{content:"\f3e9"}.fa-route:before{content:"\f4d7"}.fa-rss:before{content:"\f09e"}.fa-rss-square:before{content:"\f143"}.fa-ruble-sign:before{content:"\f158"}.fa-ruler:before{content:"\f545"}.fa-ruler-combined:before{content:"\f546"}.fa-ruler-horizontal:before{content:"\f547"}.fa-ruler-vertical:before{content:"\f548"}.fa-running:before{content:"\f70c"}.fa-rupee-sign:before{content:"\f156"}.fa-rust:before{content:"\e07a"}.fa-sad-cry:before{content:"\f5b3"}.fa-sad-tear:before{content:"\f5b4"}.fa-safari:before{content:"\f267"}.fa-salesforce:before{content:"\f83b"}.fa-sass:before{content:"\f41e"}.fa-satellite:before{content:"\f7bf"}.fa-satellite-dish:before{content:"\f7c0"}.fa-save:before{content:"\f0c7"}.fa-schlix:before{content:"\f3ea"}.fa-school:before{content:"\f549"}.fa-screwdriver:before{content:"\f54a"}.fa-scribd:before{content:"\f28a"}.fa-scroll:before{content:"\f70e"}.fa-sd-card:before{content:"\f7c2"}.fa-search:before{content:"\f002"}.fa-search-dollar:before{content:"\f688"}.fa-search-location:before{content:"\f689"}.fa-search-minus:before{content:"\f010"}.fa-search-plus:before{content:"\f00e"}.fa-searchengin:before{content:"\f3eb"}.fa-seedling:before{content:"\f4d8"}.fa-sellcast:before{content:"\f2da"}.fa-sellsy:before{content:"\f213"}.fa-server:before{content:"\f233"}.fa-servicestack:before{content:"\f3ec"}.fa-shapes:before{content:"\f61f"}.fa-share:before{content:"\f064"}.fa-share-alt:before{content:"\f1e0"}.fa-share-alt-square:before{content:"\f1e1"}.fa-share-square:before{content:"\f14d"}.fa-shekel-sign:before{content:"\f20b"}.fa-shield-alt:before{content:"\f3ed"}.fa-shield-virus:before{content:"\e06c"}.fa-ship:before{content:"\f21a"}.fa-shipping-fast:before{content:"\f48b"}.fa-shirtsinbulk:before{content:"\f214"}.fa-shoe-prints:before{content:"\f54b"}.fa-shopify:before{content:"\e057"}.fa-shopping-bag:before{content:"\f290"}.fa-shopping-basket:before{content:"\f291"}.fa-shopping-cart:before{content:"\f07a"}.fa-shopware:before{content:"\f5b5"}.fa-shower:before{content:"\f2cc"}.fa-shuttle-van:before{content:"\f5b6"}.fa-sign:before{content:"\f4d9"}.fa-sign-in-alt:before{content:"\f2f6"}.fa-sign-language:before{content:"\f2a7"}.fa-sign-out-alt:before{content:"\f2f5"}.fa-signal:before{content:"\f012"}.fa-signature:before{content:"\f5b7"}.fa-sim-card:before{content:"\f7c4"}.fa-simplybuilt:before{content:"\f215"}.fa-sink:before{content:"\e06d"}.fa-sistrix:before{content:"\f3ee"}.fa-sitemap:before{content:"\f0e8"}.fa-sith:before{content:"\f512"}.fa-skating:before{content:"\f7c5"}.fa-sketch:before{content:"\f7c6"}.fa-skiing:before{content:"\f7c9"}.fa-skiing-nordic:before{content:"\f7ca"}.fa-skull:before{content:"\f54c"}.fa-skull-crossbones:before{content:"\f714"}.fa-skyatlas:before{content:"\f216"}.fa-skype:before{content:"\f17e"}.fa-slack:before{content:"\f198"}.fa-slack-hash:before{content:"\f3ef"}.fa-slash:before{content:"\f715"}.fa-sleigh:before{content:"\f7cc"}.fa-sliders-h:before{content:"\f1de"}.fa-slideshare:before{content:"\f1e7"}.fa-smile:before{content:"\f118"}.fa-smile-beam:before{content:"\f5b8"}.fa-smile-wink:before{content:"\f4da"}.fa-smog:before{content:"\f75f"}.fa-smoking:before{content:"\f48d"}.fa-smoking-ban:before{content:"\f54d"}.fa-sms:before{content:"\f7cd"}.fa-snapchat:before{content:"\f2ab"}.fa-snapchat-ghost:before{content:"\f2ac"}.fa-snapchat-square:before{content:"\f2ad"}.fa-snowboarding:before{content:"\f7ce"}.fa-snowflake:before{content:"\f2dc"}.fa-snowman:before{content:"\f7d0"}.fa-snowplow:before{content:"\f7d2"}.fa-soap:before{content:"\e06e"}.fa-socks:before{content:"\f696"}.fa-solar-panel:before{content:"\f5ba"}.fa-sort:before{content:"\f0dc"}.fa-sort-alpha-down:before{content:"\f15d"}.fa-sort-alpha-down-alt:before{content:"\f881"}.fa-sort-alpha-up:before{content:"\f15e"}.fa-sort-alpha-up-alt:before{content:"\f882"}.fa-sort-amount-down:before{content:"\f160"}.fa-sort-amount-down-alt:before{content:"\f884"}.fa-sort-amount-up:before{content:"\f161"}.fa-sort-amount-up-alt:before{content:"\f885"}.fa-sort-down:before{content:"\f0dd"}.fa-sort-numeric-down:before{content:"\f162"}.fa-sort-numeric-down-alt:before{content:"\f886"}.fa-sort-numeric-up:before{content:"\f163"}.fa-sort-numeric-up-alt:before{content:"\f887"}.fa-sort-up:before{content:"\f0de"}.fa-soundcloud:before{content:"\f1be"}.fa-sourcetree:before{content:"\f7d3"}.fa-spa:before{content:"\f5bb"}.fa-space-shuttle:before{content:"\f197"}.fa-speakap:before{content:"\f3f3"}.fa-speaker-deck:before{content:"\f83c"}.fa-spell-check:before{content:"\f891"}.fa-spider:before{content:"\f717"}.fa-spinner:before{content:"\f110"}.fa-splotch:before{content:"\f5bc"}.fa-spotify:before{content:"\f1bc"}.fa-spray-can:before{content:"\f5bd"}.fa-square:before{content:"\f0c8"}.fa-square-full:before{content:"\f45c"}.fa-square-root-alt:before{content:"\f698"}.fa-squarespace:before{content:"\f5be"}.fa-stack-exchange:before{content:"\f18d"}.fa-stack-overflow:before{content:"\f16c"}.fa-stackpath:before{content:"\f842"}.fa-stamp:before{content:"\f5bf"}.fa-star:before{content:"\f005"}.fa-star-and-crescent:before{content:"\f699"}.fa-star-half:before{content:"\f089"}.fa-star-half-alt:before{content:"\f5c0"}.fa-star-of-david:before{content:"\f69a"}.fa-star-of-life:before{content:"\f621"}.fa-staylinked:before{content:"\f3f5"}.fa-steam:before{content:"\f1b6"}.fa-steam-square:before{content:"\f1b7"}.fa-steam-symbol:before{content:"\f3f6"}.fa-step-backward:before{content:"\f048"}.fa-step-forward:before{content:"\f051"}.fa-stethoscope:before{content:"\f0f1"}.fa-sticker-mule:before{content:"\f3f7"}.fa-sticky-note:before{content:"\f249"}.fa-stop:before{content:"\f04d"}.fa-stop-circle:before{content:"\f28d"}.fa-stopwatch:before{content:"\f2f2"}.fa-stopwatch-20:before{content:"\e06f"}.fa-store:before{content:"\f54e"}.fa-store-alt:before{content:"\f54f"}.fa-store-alt-slash:before{content:"\e070"}.fa-store-slash:before{content:"\e071"}.fa-strava:before{content:"\f428"}.fa-stream:before{content:"\f550"}.fa-street-view:before{content:"\f21d"}.fa-strikethrough:before{content:"\f0cc"}.fa-stripe:before{content:"\f429"}.fa-stripe-s:before{content:"\f42a"}.fa-stroopwafel:before{content:"\f551"}.fa-studiovinari:before{content:"\f3f8"}.fa-stumbleupon:before{content:"\f1a4"}.fa-stumbleupon-circle:before{content:"\f1a3"}.fa-subscript:before{content:"\f12c"}.fa-subway:before{content:"\f239"}.fa-suitcase:before{content:"\f0f2"}.fa-suitcase-rolling:before{content:"\f5c1"}.fa-sun:before{content:"\f185"}.fa-superpowers:before{content:"\f2dd"}.fa-superscript:before{content:"\f12b"}.fa-supple:before{content:"\f3f9"}.fa-surprise:before{content:"\f5c2"}.fa-suse:before{content:"\f7d6"}.fa-swatchbook:before{content:"\f5c3"}.fa-swift:before{content:"\f8e1"}.fa-swimmer:before{content:"\f5c4"}.fa-swimming-pool:before{content:"\f5c5"}.fa-symfony:before{content:"\f83d"}.fa-synagogue:before{content:"\f69b"}.fa-sync:before{content:"\f021"}.fa-sync-alt:before{content:"\f2f1"}.fa-syringe:before{content:"\f48e"}.fa-table:before{content:"\f0ce"}.fa-table-tennis:before{content:"\f45d"}.fa-tablet:before{content:"\f10a"}.fa-tablet-alt:before{content:"\f3fa"}.fa-tablets:before{content:"\f490"}.fa-tachometer-alt:before{content:"\f3fd"}.fa-tag:before{content:"\f02b"}.fa-tags:before{content:"\f02c"}.fa-tape:before{content:"\f4db"}.fa-tasks:before{content:"\f0ae"}.fa-taxi:before{content:"\f1ba"}.fa-teamspeak:before{content:"\f4f9"}.fa-teeth:before{content:"\f62e"}.fa-teeth-open:before{content:"\f62f"}.fa-telegram:before{content:"\f2c6"}.fa-telegram-plane:before{content:"\f3fe"}.fa-temperature-high:before{content:"\f769"}.fa-temperature-low:before{content:"\f76b"}.fa-tencent-weibo:before{content:"\f1d5"}.fa-tenge:before{content:"\f7d7"}.fa-terminal:before{content:"\f120"}.fa-text-height:before{content:"\f034"}.fa-text-width:before{content:"\f035"}.fa-th:before{content:"\f00a"}.fa-th-large:before{content:"\f009"}.fa-th-list:before{content:"\f00b"}.fa-the-red-yeti:before{content:"\f69d"}.fa-theater-masks:before{content:"\f630"}.fa-themeco:before{content:"\f5c6"}.fa-themeisle:before{content:"\f2b2"}.fa-thermometer:before{content:"\f491"}.fa-thermometer-empty:before{content:"\f2cb"}.fa-thermometer-full:before{content:"\f2c7"}.fa-thermometer-half:before{content:"\f2c9"}.fa-thermometer-quarter:before{content:"\f2ca"}.fa-thermometer-three-quarters:before{content:"\f2c8"}.fa-think-peaks:before{content:"\f731"}.fa-thumbs-down:before{content:"\f165"}.fa-thumbs-up:before{content:"\f164"}.fa-thumbtack:before{content:"\f08d"}.fa-ticket-alt:before{content:"\f3ff"}.fa-tiktok:before{content:"\e07b"}.fa-times:before{content:"\f00d"}.fa-times-circle:before{content:"\f057"}.fa-tint:before{content:"\f043"}.fa-tint-slash:before{content:"\f5c7"}.fa-tired:before{content:"\f5c8"}.fa-toggle-off:before{content:"\f204"}.fa-toggle-on:before{content:"\f205"}.fa-toilet:before{content:"\f7d8"}.fa-toilet-paper:before{content:"\f71e"}.fa-toilet-paper-slash:before{content:"\e072"}.fa-toolbox:before{content:"\f552"}.fa-tools:before{content:"\f7d9"}.fa-tooth:before{content:"\f5c9"}.fa-torah:before{content:"\f6a0"}.fa-torii-gate:before{content:"\f6a1"}.fa-tractor:before{content:"\f722"}.fa-trade-federation:before{content:"\f513"}.fa-trademark:before{content:"\f25c"}.fa-traffic-light:before{content:"\f637"}.fa-trailer:before{content:"\e041"}.fa-train:before{content:"\f238"}.fa-tram:before{content:"\f7da"}.fa-transgender:before{content:"\f224"}.fa-transgender-alt:before{content:"\f225"}.fa-trash:before{content:"\f1f8"}.fa-trash-alt:before{content:"\f2ed"}.fa-trash-restore:before{content:"\f829"}.fa-trash-restore-alt:before{content:"\f82a"}.fa-tree:before{content:"\f1bb"}.fa-trello:before{content:"\f181"}.fa-trophy:before{content:"\f091"}.fa-truck:before{content:"\f0d1"}.fa-truck-loading:before{content:"\f4de"}.fa-truck-monster:before{content:"\f63b"}.fa-truck-moving:before{content:"\f4df"}.fa-truck-pickup:before{content:"\f63c"}.fa-tshirt:before{content:"\f553"}.fa-tty:before{content:"\f1e4"}.fa-tumblr:before{content:"\f173"}.fa-tumblr-square:before{content:"\f174"}.fa-tv:before{content:"\f26c"}.fa-twitch:before{content:"\f1e8"}.fa-twitter:before{content:"\f099"}.fa-twitter-square:before{content:"\f081"}.fa-typo3:before{content:"\f42b"}.fa-uber:before{content:"\f402"}.fa-ubuntu:before{content:"\f7df"}.fa-uikit:before{content:"\f403"}.fa-umbraco:before{content:"\f8e8"}.fa-umbrella:before{content:"\f0e9"}.fa-umbrella-beach:before{content:"\f5ca"}.fa-uncharted:before{content:"\e084"}.fa-underline:before{content:"\f0cd"}.fa-undo:before{content:"\f0e2"}.fa-undo-alt:before{content:"\f2ea"}.fa-uniregistry:before{content:"\f404"}.fa-unity:before{content:"\e049"}.fa-universal-access:before{content:"\f29a"}.fa-university:before{content:"\f19c"}.fa-unlink:before{content:"\f127"}.fa-unlock:before{content:"\f09c"}.fa-unlock-alt:before{content:"\f13e"}.fa-unsplash:before{content:"\e07c"}.fa-untappd:before{content:"\f405"}.fa-upload:before{content:"\f093"}.fa-ups:before{content:"\f7e0"}.fa-usb:before{content:"\f287"}.fa-user:before{content:"\f007"}.fa-user-alt:before{content:"\f406"}.fa-user-alt-slash:before{content:"\f4fa"}.fa-user-astronaut:before{content:"\f4fb"}.fa-user-check:before{content:"\f4fc"}.fa-user-circle:before{content:"\f2bd"}.fa-user-clock:before{content:"\f4fd"}.fa-user-cog:before{content:"\f4fe"}.fa-user-edit:before{content:"\f4ff"}.fa-user-friends:before{content:"\f500"}.fa-user-graduate:before{content:"\f501"}.fa-user-injured:before{content:"\f728"}.fa-user-lock:before{content:"\f502"}.fa-user-md:before{content:"\f0f0"}.fa-user-minus:before{content:"\f503"}.fa-user-ninja:before{content:"\f504"}.fa-user-nurse:before{content:"\f82f"}.fa-user-plus:before{content:"\f234"}.fa-user-secret:before{content:"\f21b"}.fa-user-shield:before{content:"\f505"}.fa-user-slash:before{content:"\f506"}.fa-user-tag:before{content:"\f507"}.fa-user-tie:before{content:"\f508"}.fa-user-times:before{content:"\f235"}.fa-users:before{content:"\f0c0"}.fa-users-cog:before{content:"\f509"}.fa-users-slash:before{content:"\e073"}.fa-usps:before{content:"\f7e1"}.fa-ussunnah:before{content:"\f407"}.fa-utensil-spoon:before{content:"\f2e5"}.fa-utensils:before{content:"\f2e7"}.fa-vaadin:before{content:"\f408"}.fa-vector-square:before{content:"\f5cb"}.fa-venus:before{content:"\f221"}.fa-venus-double:before{content:"\f226"}.fa-venus-mars:before{content:"\f228"}.fa-vest:before{content:"\e085"}.fa-vest-patches:before{content:"\e086"}.fa-viacoin:before{content:"\f237"}.fa-viadeo:before{content:"\f2a9"}.fa-viadeo-square:before{content:"\f2aa"}.fa-vial:before{content:"\f492"}.fa-vials:before{content:"\f493"}.fa-viber:before{content:"\f409"}.fa-video:before{content:"\f03d"}.fa-video-slash:before{content:"\f4e2"}.fa-vihara:before{content:"\f6a7"}.fa-vimeo:before{content:"\f40a"}.fa-vimeo-square:before{content:"\f194"}.fa-vimeo-v:before{content:"\f27d"}.fa-vine:before{content:"\f1ca"}.fa-virus:before{content:"\e074"}.fa-virus-slash:before{content:"\e075"}.fa-viruses:before{content:"\e076"}.fa-vk:before{content:"\f189"}.fa-vnv:before{content:"\f40b"}.fa-voicemail:before{content:"\f897"}.fa-volleyball-ball:before{content:"\f45f"}.fa-volume-down:before{content:"\f027"}.fa-volume-mute:before{content:"\f6a9"}.fa-volume-off:before{content:"\f026"}.fa-volume-up:before{content:"\f028"}.fa-vote-yea:before{content:"\f772"}.fa-vr-cardboard:before{content:"\f729"}.fa-vuejs:before{content:"\f41f"}.fa-walking:before{content:"\f554"}.fa-wallet:before{content:"\f555"}.fa-warehouse:before{content:"\f494"}.fa-watchman-monitoring:before{content:"\e087"}.fa-water:before{content:"\f773"}.fa-wave-square:before{content:"\f83e"}.fa-waze:before{content:"\f83f"}.fa-weebly:before{content:"\f5cc"}.fa-weibo:before{content:"\f18a"}.fa-weight:before{content:"\f496"}.fa-weight-hanging:before{content:"\f5cd"}.fa-weixin:before{content:"\f1d7"}.fa-whatsapp:before{content:"\f232"}.fa-whatsapp-square:before{content:"\f40c"}.fa-wheelchair:before{content:"\f193"}.fa-whmcs:before{content:"\f40d"}.fa-wifi:before{content:"\f1eb"}.fa-wikipedia-w:before{content:"\f266"}.fa-wind:before{content:"\f72e"}.fa-window-close:before{content:"\f410"}.fa-window-maximize:before{content:"\f2d0"}.fa-window-minimize:before{content:"\f2d1"}.fa-window-restore:before{content:"\f2d2"}.fa-windows:before{content:"\f17a"}.fa-wine-bottle:before{content:"\f72f"}.fa-wine-glass:before{content:"\f4e3"}.fa-wine-glass-alt:before{content:"\f5ce"}.fa-wix:before{content:"\f5cf"}.fa-wizards-of-the-coast:before{content:"\f730"}.fa-wodu:before{content:"\e088"}.fa-wolf-pack-battalion:before{content:"\f514"}.fa-won-sign:before{content:"\f159"}.fa-wordpress:before{content:"\f19a"}.fa-wordpress-simple:before{content:"\f411"}.fa-wpbeginner:before{content:"\f297"}.fa-wpexplorer:before{content:"\f2de"}.fa-wpforms:before{content:"\f298"}.fa-wpressr:before{content:"\f3e4"}.fa-wrench:before{content:"\f0ad"}.fa-x-ray:before{content:"\f497"}.fa-xbox:before{content:"\f412"}.fa-xing:before{content:"\f168"}.fa-xing-square:before{content:"\f169"}.fa-y-combinator:before{content:"\f23b"}.fa-yahoo:before{content:"\f19e"}.fa-yammer:before{content:"\f840"}.fa-yandex:before{content:"\f413"}.fa-yandex-international:before{content:"\f414"}.fa-yarn:before{content:"\f7e3"}.fa-yelp:before{content:"\f1e9"}.fa-yen-sign:before{content:"\f157"}.fa-yin-yang:before{content:"\f6ad"}.fa-yoast:before{content:"\f2b1"}.fa-youtube:before{content:"\f167"}.fa-youtube-square:before{content:"\f431"}.fa-zhihu:before{content:"\f63f"}.sr-only{border:0;clip:rect(0,0,0,0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.sr-only-focusable:active,.sr-only-focusable:focus{clip:auto;height:auto;margin:0;overflow:visible;position:static;width:auto}/*!* Font Awesome Free 5.15.4 by @fontawesome - https://fontawesome.com +* License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)*/@font-face{font-family:'font awesome 5 free';font-style:normal;font-weight:900;font-display:block;src:url(../webfonts/fa-solid-900.eot);src:url(../webfonts/fa-solid-900.eot?#iefix)format("embedded-opentype"),url(../webfonts/fa-solid-900.woff2)format("woff2"),url(../webfonts/fa-solid-900.woff)format("woff"),url(../webfonts/fa-solid-900.ttf)format("truetype"),url(../webfonts/fa-solid-900.svg#fontawesome)format("svg")}.fa,.fas{font-family:'font awesome 5 free';font-weight:900}/*!* Font Awesome Free 5.15.4 by @fontawesome - https://fontawesome.com +* License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)*/@font-face{font-family:'font awesome 5 brands';font-style:normal;font-weight:400;font-display:block;src:url(../webfonts/fa-brands-400.eot);src:url(../webfonts/fa-brands-400.eot?#iefix)format("embedded-opentype"),url(../webfonts/fa-brands-400.woff2)format("woff2"),url(../webfonts/fa-brands-400.woff)format("woff"),url(../webfonts/fa-brands-400.ttf)format("truetype"),url(../webfonts/fa-brands-400.svg#fontawesome)format("svg")}.fab{font-family:'font awesome 5 brands';font-weight:400}.td-border-top{border:none;border-top:1px solid #eee}.td-border-none{border:none}.td-block-padding,.td-default main section{padding-top:4rem;padding-bottom:4rem}@media(min-width:768px){.td-block-padding,.td-default main section{padding-top:5rem;padding-bottom:5rem}}.td-overlay{position:relative}.td-overlay::after{content:"";position:absolute;top:0;right:0;bottom:0;left:0}.td-overlay--dark::after{background-color:rgba(64,63,76,.3)}.td-overlay--light::after{background-color:rgba(211,243,238,.3)}.td-overlay__inner{position:relative;z-index:1}@media(min-width:992px){.td-max-width-on-larger-screens,.td-content>pre,.td-content>.highlight,.td-content>.lead,.td-content>h1,.td-content>h2,.td-content>ul,.td-content>ol,.td-content>p,.td-content>blockquote,.td-content>dl dd,.td-content .footnotes,.td-content>.alert{max-width:80%}}.-bg-blue{color:#fff;background-color:#72a1e5}.-bg-blue p>a{color:#a0c0ee}.-bg-blue p>a:hover{color:#1e53a0}.-text-blue{color:#72a1e5}.-bg-indigo{color:#fff;background-color:#6610f2}.-bg-indigo p>a{color:#b8cff2}.-bg-indigo p>a:hover{color:#1e53a0}.-text-indigo{color:#6610f2}.-bg-purple{color:#fff;background-color:#6f42c1}.-bg-purple p>a{color:#b7cff2}.-bg-purple p>a:hover{color:#1e53a0}.-text-purple{color:#6f42c1}.-bg-pink{color:#fff;background-color:#e83e8c}.-bg-pink p>a{color:#aec9f0}.-bg-pink p>a:hover{color:#1e53a0}.-text-pink{color:#e83e8c}.-bg-red{color:#fff;background-color:#dc3545}.-bg-red p>a{color:#b4cdf1}.-bg-red p>a:hover{color:#1e53a0}.-text-red{color:#dc3545}.-bg-orange{color:#fff;background-color:#ba5a31}.-bg-orange p>a{color:#bed4f3}.-bg-orange p>a:hover{color:#1e53a0}.-text-orange{color:#ba5a31}.-bg-yellow{color:#fff;background-color:#ffc107}.-bg-yellow p>a{color:#b7cff2}.-bg-yellow p>a:hover{color:#1e53a0}.-text-yellow{color:#ffc107}.-bg-green{color:#fff;background-color:#28a745}.-bg-green p>a{color:#c6d9f4}.-bg-green p>a:hover{color:#1e53a0}.-text-green{color:#28a745}.-bg-teal{color:#fff;background-color:#20c997}.-bg-teal p>a{color:#bfd4f3}.-bg-teal p>a:hover{color:#1e53a0}.-text-teal{color:#20c997}.-bg-cyan{color:#fff;background-color:#17a2b8}.-bg-cyan p>a{color:#c6d9f4}.-bg-cyan p>a:hover{color:#1e53a0}.-text-cyan{color:#17a2b8}.-bg-white{color:#222;background-color:#fff}.-bg-white p>a{color:#72a1e5}.-bg-white p>a:hover{color:#1e53a0}.-text-white{color:#fff}.-bg-gray{color:#fff;background-color:#797676}.-bg-gray p>a{color:#bdd3f3}.-bg-gray p>a:hover{color:#1e53a0}.-text-gray{color:#797676}.-bg-gray-dark{color:#fff;background-color:#333}.-bg-gray-dark p>a{color:#e3ecfa}.-bg-gray-dark p>a:hover{color:#1e53a0}.-text-gray-dark{color:#333}.-bg-primary{color:#fff;background-color:#30638e}.-bg-primary p>a{color:#cadcf5}.-bg-primary p>a:hover{color:#1e53a0}.-text-primary{color:#30638e}.-bg-secondary{color:#fff;background-color:#ffa630}.-bg-secondary p>a{color:#abc7f0}.-bg-secondary p>a:hover{color:#1e53a0}.-text-secondary{color:#ffa630}.-bg-success{color:#fff;background-color:#3772ff}.-bg-success p>a{color:#a9c6ef}.-bg-success p>a:hover{color:#1e53a0}.-text-success{color:#3772ff}.-bg-info{color:#222;background-color:#c0e0de}.-bg-info p>a{color:#638ac1}.-bg-info p>a:hover{color:#1e53a0}.-text-info{color:#c0e0de}.-bg-warning{color:#fff;background-color:#ed6a5a}.-bg-warning p>a{color:#a5c3ee}.-bg-warning p>a:hover{color:#1e53a0}.-text-warning{color:#ed6a5a}.-bg-danger{color:#fff;background-color:#ed6a5a}.-bg-danger p>a{color:#a5c3ee}.-bg-danger p>a:hover{color:#1e53a0}.-text-danger{color:#ed6a5a}.-bg-light{color:#222;background-color:#d3f3ee}.-bg-light p>a{color:#6993d0}.-bg-light p>a:hover{color:#1e53a0}.-text-light{color:#d3f3ee}.-bg-dark{color:#fff;background-color:#403f4c}.-bg-dark p>a{color:#d9e5f8}.-bg-dark p>a:hover{color:#1e53a0}.-text-dark{color:#403f4c}.-bg-100{color:#222;background-color:#f8f9fa}.-bg-100 p>a{color:#709ee0}.-bg-100 p>a:hover{color:#1e53a0}.-text-100{color:#f8f9fa}.-bg-200{color:#222;background-color:#eee}.-bg-200 p>a{color:#6d99d8}.-bg-200 p>a:hover{color:#1e53a0}.-text-200{color:#eee}.-bg-300{color:#222;background-color:#dee2e6}.-bg-300 p>a{color:#6993cf}.-bg-300 p>a:hover{color:#1e53a0}.-text-300{color:#dee2e6}.-bg-400{color:#222;background-color:#ccc}.-bg-400 p>a{color:#6288be}.-bg-400 p>a:hover{color:#1e53a0}.-text-400{color:#ccc}.-bg-500{color:#fff;background-color:#adb5bd}.-bg-500 p>a{color:#9bbced}.-bg-500 p>a:hover{color:#1e53a0}.-text-500{color:#adb5bd}.-bg-600{color:#fff;background-color:#797676}.-bg-600 p>a{color:#bdd3f3}.-bg-600 p>a:hover{color:#1e53a0}.-text-600{color:#797676}.-bg-700{color:#fff;background-color:#495057}.-bg-700 p>a{color:#d3e2f7}.-bg-700 p>a:hover{color:#1e53a0}.-text-700{color:#495057}.-bg-800{color:#fff;background-color:#333}.-bg-800 p>a{color:#e3ecfa}.-bg-800 p>a:hover{color:#1e53a0}.-text-800{color:#333}.-bg-900{color:#fff;background-color:#222}.-bg-900 p>a{color:#ecf2fc}.-bg-900 p>a:hover{color:#1e53a0}.-text-900{color:#222}.-bg-0{color:#fff;background-color:#403f4c}.-bg-0 p>a{color:#d9e5f8}.-bg-0 p>a:hover{color:#1e53a0}.-text-0{color:#403f4c}.-bg-1{color:#fff;background-color:#30638e}.-bg-1 p>a{color:#cadcf5}.-bg-1 p>a:hover{color:#1e53a0}.-text-1{color:#30638e}.-bg-2{color:#fff;background-color:#ffa630}.-bg-2 p>a{color:#abc7f0}.-bg-2 p>a:hover{color:#1e53a0}.-text-2{color:#ffa630}.-bg-3{color:#222;background-color:#c0e0de}.-bg-3 p>a{color:#638ac1}.-bg-3 p>a:hover{color:#1e53a0}.-text-3{color:#c0e0de}.-bg-4{color:#222;background-color:#fff}.-bg-4 p>a{color:#72a1e5}.-bg-4 p>a:hover{color:#1e53a0}.-text-4{color:#fff}.-bg-5{color:#fff;background-color:#797676}.-bg-5 p>a{color:#bdd3f3}.-bg-5 p>a:hover{color:#1e53a0}.-text-5{color:#797676}.-bg-6{color:#fff;background-color:#3772ff}.-bg-6 p>a{color:#a9c6ef}.-bg-6 p>a:hover{color:#1e53a0}.-text-6{color:#3772ff}.-bg-7{color:#fff;background-color:#ed6a5a}.-bg-7 p>a{color:#a5c3ee}.-bg-7 p>a:hover{color:#1e53a0}.-text-7{color:#ed6a5a}.-bg-8{color:#fff;background-color:#403f4c}.-bg-8 p>a{color:#d9e5f8}.-bg-8 p>a:hover{color:#1e53a0}.-text-8{color:#403f4c}.-bg-9{color:#fff;background-color:#ed6a5a}.-bg-9 p>a{color:#a5c3ee}.-bg-9 p>a:hover{color:#1e53a0}.-text-9{color:#ed6a5a}.-bg-10{color:#fff;background-color:#30638e}.-bg-10 p>a{color:#cadcf5}.-bg-10 p>a:hover{color:#1e53a0}.-text-10{color:#30638e}.-bg-11{color:#fff;background-color:#ffa630}.-bg-11 p>a{color:#abc7f0}.-bg-11 p>a:hover{color:#1e53a0}.-text-11{color:#ffa630}.-bg-12{color:#222;background-color:#fff}.-bg-12 p>a{color:#72a1e5}.-bg-12 p>a:hover{color:#1e53a0}.-text-12{color:#fff}.-bg-13{color:#222;background-color:#c0e0de}.-bg-13 p>a{color:#638ac1}.-bg-13 p>a:hover{color:#1e53a0}.-text-13{color:#c0e0de}.td-box--height-min{min-height:300px}.td-box--height-med{min-height:400px}.td-box--height-max{min-height:500px}.td-box--height-full{min-height:100vh}@media(min-width:768px){.td-box--height-min{min-height:450px}.td-box--height-med{min-height:500px}.td-box--height-max{min-height:650px}}.td-box .row.section{padding-left:5vw;padding-right:5vw;flex-direction:column}.td-box .row{padding-left:5vw;padding-right:5vw;flex-direction:row}.td-box.linkbox{padding:5vh 5vw}.td-box--0{color:#fff;background-color:#403f4c}.td-box--0 .td-arrow-down::before{left:50%;margin-left:-30px;bottom:-25px;border-style:solid;border-width:25px 30px 0;border-color:#403f4c transparent transparent transparent;z-index:3;position:absolute;content:""}.td-box--0 p>a{color:#d9e5f8}.td-box--0 p>a:hover{color:#1e53a0}.td-box--10.td-box--gradient{background:#403f4c linear-gradient(180deg,#5d5c67,#403F4C)repeat-x!important}.td-box--1{color:#fff;background-color:#30638e}.td-box--1 .td-arrow-down::before{left:50%;margin-left:-30px;bottom:-25px;border-style:solid;border-width:25px 30px 0;border-color:#30638e transparent transparent transparent;z-index:3;position:absolute;content:""}.td-box--1 p>a{color:#cadcf5}.td-box--1 p>a:hover{color:#1e53a0}.td-box--11.td-box--gradient{background:#30638e linear-gradient(180deg,#4f7a9f,#30638E)repeat-x!important}.td-box--2{color:#fff;background-color:#ffa630}.td-box--2 .td-arrow-down::before{left:50%;margin-left:-30px;bottom:-25px;border-style:solid;border-width:25px 30px 0;border-color:#ffa630 transparent transparent transparent;z-index:3;position:absolute;content:""}.td-box--2 p>a{color:#abc7f0}.td-box--2 p>a:hover{color:#1e53a0}.td-box--12.td-box--gradient{background:#ffa630 linear-gradient(180deg,#ffb34f,#FFA630)repeat-x!important}.td-box--3{color:#222;background-color:#c0e0de}.td-box--3 .td-arrow-down::before{left:50%;margin-left:-30px;bottom:-25px;border-style:solid;border-width:25px 30px 0;border-color:#c0e0de transparent transparent transparent;z-index:3;position:absolute;content:""}.td-box--3 p>a{color:#638ac1}.td-box--3 p>a:hover{color:#1e53a0}.td-box--13.td-box--gradient{background:#c0e0de linear-gradient(180deg,#c9e5e3,#C0E0DE)repeat-x!important}.td-box--4{color:#222;background-color:#fff}.td-box--4 .td-arrow-down::before{left:50%;margin-left:-30px;bottom:-25px;border-style:solid;border-width:25px 30px 0;border-color:#fff transparent transparent transparent;z-index:3;position:absolute;content:""}.td-box--4 p>a{color:#72a1e5}.td-box--4 p>a:hover{color:#1e53a0}.td-box--14.td-box--gradient{background:#fff linear-gradient(180deg,white,white)repeat-x!important}.td-box--5{color:#fff;background-color:#797676}.td-box--5 .td-arrow-down::before{left:50%;margin-left:-30px;bottom:-25px;border-style:solid;border-width:25px 30px 0;border-color:#797676 transparent transparent transparent;z-index:3;position:absolute;content:""}.td-box--5 p>a{color:#bdd3f3}.td-box--5 p>a:hover{color:#1e53a0}.td-box--15.td-box--gradient{background:#797676 linear-gradient(180deg,#8d8b8b,#797676)repeat-x!important}.td-box--6{color:#fff;background-color:#3772ff}.td-box--6 .td-arrow-down::before{left:50%;margin-left:-30px;bottom:-25px;border-style:solid;border-width:25px 30px 0;border-color:#3772ff transparent transparent transparent;z-index:3;position:absolute;content:""}.td-box--6 p>a{color:#a9c6ef}.td-box--6 p>a:hover{color:#1e53a0}.td-box--16.td-box--gradient{background:#3772ff linear-gradient(180deg,#5587ff,#3772FF)repeat-x!important}.td-box--7{color:#fff;background-color:#ed6a5a}.td-box--7 .td-arrow-down::before{left:50%;margin-left:-30px;bottom:-25px;border-style:solid;border-width:25px 30px 0;border-color:#ed6a5a transparent transparent transparent;z-index:3;position:absolute;content:""}.td-box--7 p>a{color:#a5c3ee}.td-box--7 p>a:hover{color:#1e53a0}.td-box--17.td-box--gradient{background:#ed6a5a linear-gradient(180deg,#f08073,#ED6A5A)repeat-x!important}.td-box--8{color:#fff;background-color:#403f4c}.td-box--8 .td-arrow-down::before{left:50%;margin-left:-30px;bottom:-25px;border-style:solid;border-width:25px 30px 0;border-color:#403f4c transparent transparent transparent;z-index:3;position:absolute;content:""}.td-box--8 p>a{color:#d9e5f8}.td-box--8 p>a:hover{color:#1e53a0}.td-box--18.td-box--gradient{background:#403f4c linear-gradient(180deg,#5d5c67,#403F4C)repeat-x!important}.td-box--9{color:#fff;background-color:#ed6a5a}.td-box--9 .td-arrow-down::before{left:50%;margin-left:-30px;bottom:-25px;border-style:solid;border-width:25px 30px 0;border-color:#ed6a5a transparent transparent transparent;z-index:3;position:absolute;content:""}.td-box--9 p>a{color:#a5c3ee}.td-box--9 p>a:hover{color:#1e53a0}.td-box--19.td-box--gradient{background:#ed6a5a linear-gradient(180deg,#f08073,#ED6A5A)repeat-x!important}.td-box--10{color:#fff;background-color:#30638e}.td-box--10 .td-arrow-down::before{left:50%;margin-left:-30px;bottom:-25px;border-style:solid;border-width:25px 30px 0;border-color:#30638e transparent transparent transparent;z-index:3;position:absolute;content:""}.td-box--10 p>a{color:#cadcf5}.td-box--10 p>a:hover{color:#1e53a0}.td-box--110.td-box--gradient{background:#30638e linear-gradient(180deg,#4f7a9f,#30638E)repeat-x!important}.td-box--11{color:#fff;background-color:#ffa630}.td-box--11 .td-arrow-down::before{left:50%;margin-left:-30px;bottom:-25px;border-style:solid;border-width:25px 30px 0;border-color:#ffa630 transparent transparent transparent;z-index:3;position:absolute;content:""}.td-box--11 p>a{color:#abc7f0}.td-box--11 p>a:hover{color:#1e53a0}.td-box--111.td-box--gradient{background:#ffa630 linear-gradient(180deg,#ffb34f,#FFA630)repeat-x!important}.td-box--12{color:#222;background-color:#fff}.td-box--12 .td-arrow-down::before{left:50%;margin-left:-30px;bottom:-25px;border-style:solid;border-width:25px 30px 0;border-color:#fff transparent transparent transparent;z-index:3;position:absolute;content:""}.td-box--12 p>a{color:#72a1e5}.td-box--12 p>a:hover{color:#1e53a0}.td-box--112.td-box--gradient{background:#fff linear-gradient(180deg,white,white)repeat-x!important}.td-box--13{color:#222;background-color:#c0e0de}.td-box--13 .td-arrow-down::before{left:50%;margin-left:-30px;bottom:-25px;border-style:solid;border-width:25px 30px 0;border-color:#c0e0de transparent transparent transparent;z-index:3;position:absolute;content:""}.td-box--13 p>a{color:#638ac1}.td-box--13 p>a:hover{color:#1e53a0}.td-box--113.td-box--gradient{background:#c0e0de linear-gradient(180deg,#c9e5e3,#C0E0DE)repeat-x!important}.td-box--blue{color:#fff;background-color:#72a1e5}.td-box--blue .td-arrow-down::before{left:50%;margin-left:-30px;bottom:-25px;border-style:solid;border-width:25px 30px 0;border-color:#72a1e5 transparent transparent transparent;z-index:3;position:absolute;content:""}.td-box--blue p>a{color:#a0c0ee}.td-box--blue p>a:hover{color:#1e53a0}.td-box--1blue.td-box--gradient{background:#72a1e5 linear-gradient(180deg,#87afe9,#72A1E5)repeat-x!important}.td-box--indigo{color:#fff;background-color:#6610f2}.td-box--indigo .td-arrow-down::before{left:50%;margin-left:-30px;bottom:-25px;border-style:solid;border-width:25px 30px 0;border-color:#6610f2 transparent transparent transparent;z-index:3;position:absolute;content:""}.td-box--indigo p>a{color:#b8cff2}.td-box--indigo p>a:hover{color:#1e53a0}.td-box--1indigo.td-box--gradient{background:#6610f2 linear-gradient(180deg,#7d34f4,#6610f2)repeat-x!important}.td-box--purple{color:#fff;background-color:#6f42c1}.td-box--purple .td-arrow-down::before{left:50%;margin-left:-30px;bottom:-25px;border-style:solid;border-width:25px 30px 0;border-color:#6f42c1 transparent transparent transparent;z-index:3;position:absolute;content:""}.td-box--purple p>a{color:#b7cff2}.td-box--purple p>a:hover{color:#1e53a0}.td-box--1purple.td-box--gradient{background:#6f42c1 linear-gradient(180deg,#855eca,#6f42c1)repeat-x!important}.td-box--pink{color:#fff;background-color:#e83e8c}.td-box--pink .td-arrow-down::before{left:50%;margin-left:-30px;bottom:-25px;border-style:solid;border-width:25px 30px 0;border-color:#e83e8c transparent transparent transparent;z-index:3;position:absolute;content:""}.td-box--pink p>a{color:#aec9f0}.td-box--pink p>a:hover{color:#1e53a0}.td-box--1pink.td-box--gradient{background:#e83e8c linear-gradient(180deg,#eb5b9d,#e83e8c)repeat-x!important}.td-box--red{color:#fff;background-color:#dc3545}.td-box--red .td-arrow-down::before{left:50%;margin-left:-30px;bottom:-25px;border-style:solid;border-width:25px 30px 0;border-color:#dc3545 transparent transparent transparent;z-index:3;position:absolute;content:""}.td-box--red p>a{color:#b4cdf1}.td-box--red p>a:hover{color:#1e53a0}.td-box--1red.td-box--gradient{background:#dc3545 linear-gradient(180deg,#e15361,#dc3545)repeat-x!important}.td-box--orange{color:#fff;background-color:#ba5a31}.td-box--orange .td-arrow-down::before{left:50%;margin-left:-30px;bottom:-25px;border-style:solid;border-width:25px 30px 0;border-color:#ba5a31 transparent transparent transparent;z-index:3;position:absolute;content:""}.td-box--orange p>a{color:#bed4f3}.td-box--orange p>a:hover{color:#1e53a0}.td-box--1orange.td-box--gradient{background:#ba5a31 linear-gradient(180deg,#c47350,#BA5A31)repeat-x!important}.td-box--yellow{color:#fff;background-color:#ffc107}.td-box--yellow .td-arrow-down::before{left:50%;margin-left:-30px;bottom:-25px;border-style:solid;border-width:25px 30px 0;border-color:#ffc107 transparent transparent transparent;z-index:3;position:absolute;content:""}.td-box--yellow p>a{color:#b7cff2}.td-box--yellow p>a:hover{color:#1e53a0}.td-box--1yellow.td-box--gradient{background:#ffc107 linear-gradient(180deg,#ffca2c,#ffc107)repeat-x!important}.td-box--green{color:#fff;background-color:#28a745}.td-box--green .td-arrow-down::before{left:50%;margin-left:-30px;bottom:-25px;border-style:solid;border-width:25px 30px 0;border-color:#28a745 transparent transparent transparent;z-index:3;position:absolute;content:""}.td-box--green p>a{color:#c6d9f4}.td-box--green p>a:hover{color:#1e53a0}.td-box--1green.td-box--gradient{background:#28a745 linear-gradient(180deg,#48b461,#28a745)repeat-x!important}.td-box--teal{color:#fff;background-color:#20c997}.td-box--teal .td-arrow-down::before{left:50%;margin-left:-30px;bottom:-25px;border-style:solid;border-width:25px 30px 0;border-color:#20c997 transparent transparent transparent;z-index:3;position:absolute;content:""}.td-box--teal p>a{color:#bfd4f3}.td-box--teal p>a:hover{color:#1e53a0}.td-box--1teal.td-box--gradient{background:#20c997 linear-gradient(180deg,#41d1a7,#20c997)repeat-x!important}.td-box--cyan{color:#fff;background-color:#17a2b8}.td-box--cyan .td-arrow-down::before{left:50%;margin-left:-30px;bottom:-25px;border-style:solid;border-width:25px 30px 0;border-color:#17a2b8 transparent transparent transparent;z-index:3;position:absolute;content:""}.td-box--cyan p>a{color:#c6d9f4}.td-box--cyan p>a:hover{color:#1e53a0}.td-box--1cyan.td-box--gradient{background:#17a2b8 linear-gradient(180deg,#3ab0c3,#17a2b8)repeat-x!important}.td-box--white{color:#222;background-color:#fff}.td-box--white .td-arrow-down::before{left:50%;margin-left:-30px;bottom:-25px;border-style:solid;border-width:25px 30px 0;border-color:#fff transparent transparent transparent;z-index:3;position:absolute;content:""}.td-box--white p>a{color:#72a1e5}.td-box--white p>a:hover{color:#1e53a0}.td-box--1white.td-box--gradient{background:#fff linear-gradient(180deg,white,#fff)repeat-x!important}.td-box--gray{color:#fff;background-color:#797676}.td-box--gray .td-arrow-down::before{left:50%;margin-left:-30px;bottom:-25px;border-style:solid;border-width:25px 30px 0;border-color:#797676 transparent transparent transparent;z-index:3;position:absolute;content:""}.td-box--gray p>a{color:#bdd3f3}.td-box--gray p>a:hover{color:#1e53a0}.td-box--1gray.td-box--gradient{background:#797676 linear-gradient(180deg,#8d8b8b,#797676)repeat-x!important}.td-box--gray-dark{color:#fff;background-color:#333}.td-box--gray-dark .td-arrow-down::before{left:50%;margin-left:-30px;bottom:-25px;border-style:solid;border-width:25px 30px 0;border-color:#333 transparent transparent transparent;z-index:3;position:absolute;content:""}.td-box--gray-dark p>a{color:#e3ecfa}.td-box--gray-dark p>a:hover{color:#1e53a0}.td-box--1gray-dark.td-box--gradient{background:#333 linear-gradient(180deg,#525252,#333)repeat-x!important}.td-box--primary{color:#fff;background-color:#30638e}.td-box--primary .td-arrow-down::before{left:50%;margin-left:-30px;bottom:-25px;border-style:solid;border-width:25px 30px 0;border-color:#30638e transparent transparent transparent;z-index:3;position:absolute;content:""}.td-box--primary p>a{color:#cadcf5}.td-box--primary p>a:hover{color:#1e53a0}.td-box--1primary.td-box--gradient{background:#30638e linear-gradient(180deg,#4f7a9f,#30638E)repeat-x!important}.td-box--secondary{color:#fff;background-color:#ffa630}.td-box--secondary .td-arrow-down::before{left:50%;margin-left:-30px;bottom:-25px;border-style:solid;border-width:25px 30px 0;border-color:#ffa630 transparent transparent transparent;z-index:3;position:absolute;content:""}.td-box--secondary p>a{color:#abc7f0}.td-box--secondary p>a:hover{color:#1e53a0}.td-box--1secondary.td-box--gradient{background:#ffa630 linear-gradient(180deg,#ffb34f,#FFA630)repeat-x!important}.td-box--success{color:#fff;background-color:#3772ff}.td-box--success .td-arrow-down::before{left:50%;margin-left:-30px;bottom:-25px;border-style:solid;border-width:25px 30px 0;border-color:#3772ff transparent transparent transparent;z-index:3;position:absolute;content:""}.td-box--success p>a{color:#a9c6ef}.td-box--success p>a:hover{color:#1e53a0}.td-box--1success.td-box--gradient{background:#3772ff linear-gradient(180deg,#5587ff,#3772FF)repeat-x!important}.td-box--info{color:#222;background-color:#c0e0de}.td-box--info .td-arrow-down::before{left:50%;margin-left:-30px;bottom:-25px;border-style:solid;border-width:25px 30px 0;border-color:#c0e0de transparent transparent transparent;z-index:3;position:absolute;content:""}.td-box--info p>a{color:#638ac1}.td-box--info p>a:hover{color:#1e53a0}.td-box--1info.td-box--gradient{background:#c0e0de linear-gradient(180deg,#c9e5e3,#C0E0DE)repeat-x!important}.td-box--warning{color:#fff;background-color:#ed6a5a}.td-box--warning .td-arrow-down::before{left:50%;margin-left:-30px;bottom:-25px;border-style:solid;border-width:25px 30px 0;border-color:#ed6a5a transparent transparent transparent;z-index:3;position:absolute;content:""}.td-box--warning p>a{color:#a5c3ee}.td-box--warning p>a:hover{color:#1e53a0}.td-box--1warning.td-box--gradient{background:#ed6a5a linear-gradient(180deg,#f08073,#ED6A5A)repeat-x!important}.td-box--danger{color:#fff;background-color:#ed6a5a}.td-box--danger .td-arrow-down::before{left:50%;margin-left:-30px;bottom:-25px;border-style:solid;border-width:25px 30px 0;border-color:#ed6a5a transparent transparent transparent;z-index:3;position:absolute;content:""}.td-box--danger p>a{color:#a5c3ee}.td-box--danger p>a:hover{color:#1e53a0}.td-box--1danger.td-box--gradient{background:#ed6a5a linear-gradient(180deg,#f08073,#ED6A5A)repeat-x!important}.td-box--light{color:#222;background-color:#d3f3ee}.td-box--light .td-arrow-down::before{left:50%;margin-left:-30px;bottom:-25px;border-style:solid;border-width:25px 30px 0;border-color:#d3f3ee transparent transparent transparent;z-index:3;position:absolute;content:""}.td-box--light p>a{color:#6993d0}.td-box--light p>a:hover{color:#1e53a0}.td-box--1light.td-box--gradient{background:#d3f3ee linear-gradient(180deg,#daf5f1,#D3F3EE)repeat-x!important}.td-box--dark{color:#fff;background-color:#403f4c}.td-box--dark .td-arrow-down::before{left:50%;margin-left:-30px;bottom:-25px;border-style:solid;border-width:25px 30px 0;border-color:#403f4c transparent transparent transparent;z-index:3;position:absolute;content:""}.td-box--dark p>a{color:#d9e5f8}.td-box--dark p>a:hover{color:#1e53a0}.td-box--1dark.td-box--gradient{background:#403f4c linear-gradient(180deg,#5d5c67,#403F4C)repeat-x!important}.td-box--100{color:#222;background-color:#f8f9fa}.td-box--100 .td-arrow-down::before{left:50%;margin-left:-30px;bottom:-25px;border-style:solid;border-width:25px 30px 0;border-color:#f8f9fa transparent transparent transparent;z-index:3;position:absolute;content:""}.td-box--100 p>a{color:#709ee0}.td-box--100 p>a:hover{color:#1e53a0}.td-box--1100.td-box--gradient{background:#f8f9fa linear-gradient(180deg,#f9fafb,#f8f9fa)repeat-x!important}.td-box--200{color:#222;background-color:#eee}.td-box--200 .td-arrow-down::before{left:50%;margin-left:-30px;bottom:-25px;border-style:solid;border-width:25px 30px 0;border-color:#eee transparent transparent transparent;z-index:3;position:absolute;content:""}.td-box--200 p>a{color:#6d99d8}.td-box--200 p>a:hover{color:#1e53a0}.td-box--1200.td-box--gradient{background:#eee linear-gradient(180deg,#f1f1f1,#eee)repeat-x!important}.td-box--300{color:#222;background-color:#dee2e6}.td-box--300 .td-arrow-down::before{left:50%;margin-left:-30px;bottom:-25px;border-style:solid;border-width:25px 30px 0;border-color:#dee2e6 transparent transparent transparent;z-index:3;position:absolute;content:""}.td-box--300 p>a{color:#6993cf}.td-box--300 p>a:hover{color:#1e53a0}.td-box--1300.td-box--gradient{background:#dee2e6 linear-gradient(180deg,#e3e6ea,#dee2e6)repeat-x!important}.td-box--400{color:#222;background-color:#ccc}.td-box--400 .td-arrow-down::before{left:50%;margin-left:-30px;bottom:-25px;border-style:solid;border-width:25px 30px 0;border-color:#ccc transparent transparent transparent;z-index:3;position:absolute;content:""}.td-box--400 p>a{color:#6288be}.td-box--400 p>a:hover{color:#1e53a0}.td-box--1400.td-box--gradient{background:#ccc linear-gradient(180deg,#d4d4d4,#ccc)repeat-x!important}.td-box--500{color:#fff;background-color:#adb5bd}.td-box--500 .td-arrow-down::before{left:50%;margin-left:-30px;bottom:-25px;border-style:solid;border-width:25px 30px 0;border-color:#adb5bd transparent transparent transparent;z-index:3;position:absolute;content:""}.td-box--500 p>a{color:#9bbced}.td-box--500 p>a:hover{color:#1e53a0}.td-box--1500.td-box--gradient{background:#adb5bd linear-gradient(180deg,#b9c0c7,#adb5bd)repeat-x!important}.td-box--600{color:#fff;background-color:#797676}.td-box--600 .td-arrow-down::before{left:50%;margin-left:-30px;bottom:-25px;border-style:solid;border-width:25px 30px 0;border-color:#797676 transparent transparent transparent;z-index:3;position:absolute;content:""}.td-box--600 p>a{color:#bdd3f3}.td-box--600 p>a:hover{color:#1e53a0}.td-box--1600.td-box--gradient{background:#797676 linear-gradient(180deg,#8d8b8b,#797676)repeat-x!important}.td-box--700{color:#fff;background-color:#495057}.td-box--700 .td-arrow-down::before{left:50%;margin-left:-30px;bottom:-25px;border-style:solid;border-width:25px 30px 0;border-color:#495057 transparent transparent transparent;z-index:3;position:absolute;content:""}.td-box--700 p>a{color:#d3e2f7}.td-box--700 p>a:hover{color:#1e53a0}.td-box--1700.td-box--gradient{background:#495057 linear-gradient(180deg,#646a70,#495057)repeat-x!important}.td-box--800{color:#fff;background-color:#333}.td-box--800 .td-arrow-down::before{left:50%;margin-left:-30px;bottom:-25px;border-style:solid;border-width:25px 30px 0;border-color:#333 transparent transparent transparent;z-index:3;position:absolute;content:""}.td-box--800 p>a{color:#e3ecfa}.td-box--800 p>a:hover{color:#1e53a0}.td-box--1800.td-box--gradient{background:#333 linear-gradient(180deg,#525252,#333)repeat-x!important}.td-box--900{color:#fff;background-color:#222}.td-box--900 .td-arrow-down::before{left:50%;margin-left:-30px;bottom:-25px;border-style:solid;border-width:25px 30px 0;border-color:#222 transparent transparent transparent;z-index:3;position:absolute;content:""}.td-box--900 p>a{color:#ecf2fc}.td-box--900 p>a:hover{color:#1e53a0}.td-box--1900.td-box--gradient{background:#222 linear-gradient(180deg,#434343,#222)repeat-x!important}.td-blog .td-rss-button{position:absolute;top:5.5rem;right:1rem;z-index:22}.td-content .highlight{margin:2rem 0;padding:0}.td-content .highlight pre{margin:0;padding:1rem}.td-content p code,.td-content li>code,.td-content table code{color:inherit;padding:.2em .4em;margin:0;font-size:85%;word-break:normal;background-color:rgba(0,0,0,5%);border-radius:.25rem}.td-content p code br,.td-content li>code br,.td-content table code br{display:none}.td-content pre{word-wrap:normal;background-color:#f8f9fa;padding:1rem}.td-content pre>code{background-color:inherit!important;padding:0;margin:0;font-size:100%;word-break:normal;white-space:pre;border:0}.td-content pre.mermaid{background-color:inherit;font-size:0}.td-navbar-cover{background:#30638e}@media(min-width:768px){.td-navbar-cover{background:0 0!important}.td-navbar-cover .nav-link{text-shadow:1px 1px 2px #403f4c}}.td-navbar-cover.navbar-bg-onscroll .nav-link{text-shadow:none}.navbar-bg-onscroll{background:#30638e!important;opacity:inherit}.td-navbar{background:#30638e;min-height:4rem;margin:0;z-index:32}@media(min-width:768px){.td-navbar{position:fixed;top:0;width:100%}}.td-navbar .navbar-brand{text-transform:none;text-align:middle}.td-navbar .navbar-brand .nav-link{display:inline-block;margin-right:-30px}.td-navbar .navbar-brand svg{display:inline-block;margin:0 10px;height:30px}.td-navbar .nav-link{text-transform:none;font-weight:700}.td-navbar .td-search-input{border:none;color:rgba(255,255,255,.75)}.td-navbar .td-search-input::-webkit-input-placeholder{color:rgba(255,255,255,.75)}.td-navbar .td-search-input:-moz-placeholder{color:rgba(255,255,255,.75)}.td-navbar .td-search-input::-moz-placeholder{color:rgba(255,255,255,.75)}.td-navbar .td-search-input:-ms-input-placeholder{color:rgba(255,255,255,.75)}.td-navbar .dropdown{min-width:100px}@media(max-width:991.98px){.td-navbar{padding-right:.5rem;padding-left:.75rem}.td-navbar .td-navbar-nav-scroll{max-width:100%;height:2.5rem;margin-top:.25rem;overflow:hidden;font-size:.875rem}.td-navbar .td-navbar-nav-scroll .nav-link{padding-right:.25rem;padding-left:0}.td-navbar .td-navbar-nav-scroll .navbar-nav{padding-bottom:2rem;overflow-x:auto;white-space:nowrap;-webkit-overflow-scrolling:touch}}#main_navbar li i{padding-right:.5em}#main_navbar li i:before{display:inline-block;text-align:center;min-width:1em}#main_navbar .alert{background-color:inherit;padding:0;color:#ffa630;border:0;font-weight:inherit}#main_navbar .alert:before{display:inline-block;font-style:normal;font-variant:normal;text-rendering:auto;-webkit-font-smoothing:antialiased;font-family:"font awesome 5 free";font-weight:900;content:"\f0d9";padding-left:.5em;padding-right:.5em}nav.foldable-nav#td-section-nav{position:relative}nav.foldable-nav#td-section-nav label{margin-bottom:0;width:100%}nav.foldable-nav .td-sidebar-nav__section,nav.foldable-nav .with-child ul{list-style:none;padding:0;margin:0}nav.foldable-nav .ul-1>li{padding-left:1.5em}nav.foldable-nav ul.foldable{max-height:0;overflow:hidden;transition:max-height .5s cubic-bezier(0,1,0,1)}nav.foldable-nav input:checked~ul.foldable{max-height:100000vmax;transition:max-height 1s ease-in-out}nav.foldable-nav input[type=checkbox]{display:none}nav.foldable-nav .with-child,nav.foldable-nav .without-child{position:relative;padding-left:1.5em}nav.foldable-nav .ul-1 .with-child>label:before{display:inline-block;font-style:normal;font-variant:normal;text-rendering:auto;-webkit-font-smoothing:antialiased;font-family:"font awesome 5 free";font-weight:900;content:"\f0da";position:absolute;left:.1em;padding-left:.4em;padding-right:.4em;font-size:1em;color:#222;transition:all .5s}nav.foldable-nav .ul-1 .with-child>label:before:hover{transform:rotate(90deg)}nav.foldable-nav .ul-1 .with-child>input:checked~label:before{color:#30638e;transform:rotate(90deg);transition:transform .5s}nav.foldable-nav .with-child ul{margin-top:.1em}@media(hover:hover) and (pointer:fine){nav.foldable-nav .ul-1 .with-child>label:hover:before{color:#30638e;transform:rotate(30deg);transition:transform .5s}nav.foldable-nav .ul-1 .with-child>input:checked~label:hover:before{color:#30638e;transform:rotate(60deg)!important;transition:transform .5s}}.td-sidebar-nav{padding-right:.5rem;margin-right:-15px;margin-left:-15px}@media(min-width:768px){@supports((position:-webkit-sticky) or (position:sticky)){.td-sidebar-nav{max-height:calc(100vh - 10rem);overflow-y:auto}}}@media(min-width:768px){.td-sidebar-nav{display:block!important}}.td-sidebar-nav__section{padding-left:0}.td-sidebar-nav__section li{list-style:none}.td-sidebar-nav__section ul{padding:0;margin:0}@media(min-width:768px){.td-sidebar-nav__section .ul-1 ul{padding-left:1.5em}}.td-sidebar-nav__section-title{display:block;font-weight:500}.td-sidebar-nav__section-title .active{font-weight:700}.td-sidebar-nav__section-title a{color:#222}.td-sidebar-nav .td-sidebar-link{display:block;padding-bottom:.375rem}.td-sidebar-nav .td-sidebar-link__page{color:#495057;font-weight:300}.td-sidebar-nav a:hover{color:#72a1e5;text-decoration:none}.td-sidebar-nav a.active{font-weight:700}.td-sidebar-nav .dropdown a{color:#495057}.td-sidebar-nav .dropdown .nav-link{padding:0 0 1rem}.td-sidebar-nav>.td-sidebar-nav__section{padding-top:.5rem;padding-left:1.5rem}.td-sidebar-nav li i{padding-right:.5em}.td-sidebar-nav li i:before{display:inline-block;text-align:center;min-width:1em}.td-sidebar-nav .td-sidebar-link.tree-root{font-weight:700;color:#30638e;border-bottom:1px #30638e solid;margin-bottom:1rem}.td-sidebar{padding-bottom:1rem}@media(min-width:768px){.td-sidebar{padding-top:4rem;background-color:rgba(48,99,142,3%);padding-right:1rem;border-right:1px solid #dee2e6}}.td-sidebar__toggle{line-height:1;color:#222;margin:1rem}.td-sidebar__search{padding:1rem 15px;margin-right:-15px;margin-left:-15px}.td-sidebar__inner{order:0}@media(min-width:768px){@supports((position:-webkit-sticky) or (position:sticky)){.td-sidebar__inner{position:-webkit-sticky;position:sticky;top:4rem;z-index:10;height:calc(100vh - 6rem)}}}@media(min-width:1200px){.td-sidebar__inner{flex:0 1 320px}}.td-sidebar__inner .td-search-box{width:100%}.td-sidebar #content-desktop{display:block}.td-sidebar #content-mobile{display:none}@media(max-width:991.98px){.td-sidebar #content-desktop{display:none}.td-sidebar #content-mobile{display:block}}.td-sidebar-toc{border-left:1px solid #dee2e6;order:2;padding-top:.75rem;padding-bottom:1.5rem;vertical-align:top}@supports((position:-webkit-sticky) or (position:sticky)){.td-sidebar-toc{position:-webkit-sticky;position:sticky;top:4rem;height:calc(100vh - 10rem);overflow-y:auto}}.td-page-meta a{display:block;font-weight:500}.td-toc a{display:block;font-weight:300;padding-bottom:.25rem}.td-toc li{list-style:none;display:block}.td-toc li li{margin-left:.5rem}.td-toc #TableOfContents a{color:#797676}.td-toc #TableOfContents a:hover{color:#72a1e5;text-decoration:none}.td-toc ul{padding-left:0}.btn{border-radius:1rem}.btn-lg,.btn-group-lg>.btn{border-radius:2rem}.btn-sm,.btn-group-sm>.btn{border-radius:1rem}@media print{.td-breadcrumbs{display:none!important}}.td-breadcrumbs .breadcrumb{background:inherit;padding-left:0;padding-top:0}.alert{font-weight:500;background:#fff;color:inherit;border-radius:0}.alert-primary{border-style:solid;border-color:#30638e;border-width:0 0 0 4px}.alert-primary .alert-heading{color:#30638e}.alert-secondary{border-style:solid;border-color:#ffa630;border-width:0 0 0 4px}.alert-secondary .alert-heading{color:#ffa630}.alert-success{border-style:solid;border-color:#3772ff;border-width:0 0 0 4px}.alert-success .alert-heading{color:#3772ff}.alert-info{border-style:solid;border-color:#c0e0de;border-width:0 0 0 4px}.alert-info .alert-heading{color:#c0e0de}.alert-warning{border-style:solid;border-color:#ed6a5a;border-width:0 0 0 4px}.alert-warning .alert-heading{color:#ed6a5a}.alert-danger{border-style:solid;border-color:#ed6a5a;border-width:0 0 0 4px}.alert-danger .alert-heading{color:#ed6a5a}.alert-light{border-style:solid;border-color:#d3f3ee;border-width:0 0 0 4px}.alert-light .alert-heading{color:#d3f3ee}.alert-dark{border-style:solid;border-color:#403f4c;border-width:0 0 0 4px}.alert-dark .alert-heading{color:#403f4c}.td-content{order:1}.td-content p,.td-content li,.td-content td{font-weight:400}.td-content>h1{font-weight:700;margin-bottom:1rem}.td-content>h2{margin-bottom:1rem}.td-content>h2:not(:first-child){margin-top:3rem}.td-content>h2+h3{margin-top:1rem}.td-content>h3,.td-content>h4,.td-content>h5,.td-content>h6{margin-bottom:1rem;margin-top:2rem}.td-content>blockquote{padding:0 0 0 1rem;margin-bottom:1rem;color:#797676;border-left:6px solid #ffa630}.td-content>ul li,.td-content>ol li{margin-bottom:.25rem}.td-content strong{font-weight:700}.td-content .alert:not(:first-child){margin-top:2rem;margin-bottom:2rem}.td-content .lead{margin-bottom:1.5rem}.td-title{margin-top:1rem;margin-bottom:.5rem}@media(min-width:576px){.td-title{font-size:3rem}}.td-search-input{background:0 0;max-width:90%;border-radius:1rem;font-family:"font awesome 5 free",open sans,-apple-system,BlinkMacSystemFont,segoe ui,Roboto,helvetica neue,Arial,sans-serif,apple color emoji,segoe ui emoji,segoe ui symbol}.td-search-input.form-control:focus{border-color:#f5f8fb;box-shadow:0 0 0 2px #82afd5;color:inherit}.popover.offline-search-result{max-width:90%}.popover.offline-search-result .card,.popover.offline-search-result .td-content .highlight,.td-content .popover.offline-search-result .highlight{margin-bottom:.5rem}.popover.offline-search-result .card .card-header,.popover.offline-search-result .td-content .highlight .card-header,.td-content .popover.offline-search-result .highlight .card-header{font-weight:700}.td-outer{display:flex;flex-direction:column;height:100vh}@media(min-width:768px){.td-default main>section:first-of-type{padding-top:8rem}}.td-main{flex-grow:1}.td-main main{padding-bottom:2rem}@media(min-width:768px){.td-main main{padding-top:5.5rem}}.td-cover-block--height-min{min-height:300px}.td-cover-block--height-med{min-height:400px}.td-cover-block--height-max{min-height:500px}.td-cover-block--height-full{min-height:100vh}@media(min-width:768px){.td-cover-block--height-min{min-height:450px}.td-cover-block--height-med{min-height:500px}.td-cover-block--height-max{min-height:650px}}.td-cover-logo{margin-right:.5em}.td-cover-block{position:relative;padding-top:5rem;padding-bottom:5rem;background-repeat:no-repeat;background-position:50% 0;background-size:cover}.td-cover-block>.byline{position:absolute;bottom:2px;right:4px}.td-bg-arrow-wrapper{position:relative}.section-index .entry{padding:.75rem}.section-index h5{margin-bottom:0}.section-index h5 a{font-weight:700}.section-index p{margin-top:0}.pageinfo{font-weight:500;background:#f8f9fa;color:inherit;border-radius:0;margin:2rem;padding:1.5rem;padding-bottom:.5rem}.pageinfo-primary{border-style:solid;border-color:#30638e}.pageinfo-secondary{border-style:solid;border-color:#ffa630}.pageinfo-success{border-style:solid;border-color:#3772ff}.pageinfo-info{border-style:solid;border-color:#c0e0de}.pageinfo-warning{border-style:solid;border-color:#ed6a5a}.pageinfo-danger{border-style:solid;border-color:#ed6a5a}.pageinfo-light{border-style:solid;border-color:#d3f3ee}.pageinfo-dark{border-style:solid;border-color:#403f4c}.taxonomy-terms-article{width:100%;clear:both;font-size:.8rem}.taxonomy-terms-article .taxonomy-title{display:inline;font-size:1.25em;height:1em;line-height:1em;margin-right:.5em;padding:0}.taxonomy-terms-cloud{width:100%;clear:both;font-size:.8rem}.taxonomy-terms-cloud .taxonomy-title{display:inline-block;width:100%;font-size:1rem;font-weight:700;color:#30638e;border-bottom:1px #30638e solid;margin-bottom:1em;padding-bottom:.375rem;margin-top:1em}.taxonomy-terms-page{max-width:800px;margin:auto}.taxonomy-terms-page h1{margin-bottom:1em}.taxonomy-terms-page .taxonomy-terms-cloud{font-size:1em}.taxonomy-terms-page .taxonomy-terms-cloud li{display:block}.taxonomy-terms-page .taxo-text-tags li+li::before{content:none}.taxonomy-terms-page .taxo-fruits .taxonomy-count,.taxonomy-terms-page .taxo-fruits .taxonomy-label{display:inherit;font-size:1rem;margin:0;padding:0;padding-right:.5em}.taxonomy-terms-page .taxo-fruits .taxonomy-count::before{content:"("}.taxonomy-terms-page .taxo-fruits .taxonomy-count::after{content:")"}.taxonomy-terms{list-style:none;margin:0;overflow:hidden;padding:0;display:inline}.taxonomy-terms li{display:inline;overflow-wrap:break-word;word-wrap:break-word;-ms-word-break:break-all;word-break:break-all;word-break:break-word;-ms-hyphens:auto;-webkit-hyphens:auto;hyphens:auto}.taxonomy-count{font-size:.8em;line-height:1.25em;display:inline-block;padding-left:.6em;padding-right:.6em;margin-left:.6em;text-align:center;border-radius:1em;background-color:#fff}.taxonomy-term{background:#eee;border-width:0;border-radius:0 3px 3px 0;color:#797676;display:inline-block;font-size:1em;line-height:1.5em;min-height:1.5em;max-width:100%;padding:0 .5em 0 1em;position:relative;margin:0 .5em .2em 0;text-decoration:none;-webkit-transition:color .2s;-webkit-clip-path:polygon(100% 0,100% 100%,.8em 100%,0 50%,.8em 0);clip-path:polygon(100% 0,100% 100%,.8em 100%,0 50%,.8em 0)}.taxonomy-term:hover{background-color:#30638e;color:#fff}.taxonomy-term:hover .taxonomy-count{color:#403f4c!important}.taxonomy-term:hover::before{background:#30638e}.taxo-text-tags .taxonomy-term{background:0 0;border-width:0;border-radius:0;color:#797676;font-size:1em;line-height:1.5em;min-height:1.5em;max-width:100%;padding:0;position:relative;margin:0;text-decoration:none;-webkit-clip-path:none;clip-path:none}.taxo-text-tags .taxonomy-term:hover{background:0 0;color:#3176d9}.taxo-text-tags .taxonomy-term:hover .taxonomy-count{color:#403f4c!important}.taxo-text-tags .taxonomy-term:hover::before{background:0 0}.taxo-text-tags li+li::before{content:"|";color:#797676;margin-right:.2em}.taxo-text-tags .taxonomy-count{font-size:1em;line-height:1.25em;display:inline-block;padding:0;margin:0;text-align:center;border-radius:0;background:0 0;vertical-align:super;font-size:.75em}.taxo-text-tags .taxonomy-term:hover .taxonomy-count{color:#3176d9!important}.taxo-fruits .taxonomy-term[data-taxonomy-term]::before{font-style:normal;font-variant:normal;text-rendering:auto;-webkit-font-smoothing:antialiased;font-family:"font awesome 5 free";padding-right:.5em;font-size:2em;min-width:1.5em;display:inline-block}.taxo-fruits .taxonomy-term[data-taxonomy-term=apple]::before{content:"\f5d1";color:red}.taxo-fruits .taxonomy-term[data-taxonomy-term=carrot]::before{content:"\f787";color:orange}.taxo-fruits .taxonomy-term[data-taxonomy-term=lemon]::before{content:"\f094";color:#32cd32}.taxo-fruits .taxonomy-term[data-taxonomy-term=pepper]::before{content:"\f816";color:darkred}.taxo-fruits .taxonomy-term{background:0 0;border-width:0;border-radius:0;color:#797676;font-size:1em;line-height:2.5em;max-width:100%;padding:0;position:relative;margin:0;text-decoration:none;-webkit-clip-path:none;clip-path:none}.taxo-fruits .taxonomy-term:hover{background:0 0;color:#3176d9}.taxo-fruits .taxonomy-term:hover .taxonomy-count{color:#403f4c!important}.taxo-fruits .taxonomy-term:hover::before{background:0 0;text-shadow:0 0 3px #222}.taxo-fruits .taxonomy-count,.taxo-fruits .taxonomy-label{display:none}.taxo-fruits.taxonomy-terms-article{margin-bottom:1rem}.taxo-fruits.taxonomy-terms-article .taxonomy-title{display:none}.taxonomy-taxonomy-page{max-width:800px;margin:auto}.taxonomy-taxonomy-page h1{margin-bottom:1em}.article-meta{margin-bottom:1.5rem}.article-teaser.article-type-docs h3 a:before{display:inline-block;font-style:normal;font-variant:normal;text-rendering:auto;-webkit-font-smoothing:antialiased;font-family:"font awesome 5 free";content:"\f02d";padding-right:.5em}.article-teaser.article-type-blog h3 a:before{display:inline-block;font-style:normal;font-variant:normal;text-rendering:auto;-webkit-font-smoothing:antialiased;font-family:"font awesome 5 free";content:"\f781";padding-right:.5em}.all-taxonomy-terms{font-weight:500;line-height:1.2;font-size:1.5rem}.all-taxonomy-terms:before{display:inline-block;font-style:normal;font-variant:normal;text-rendering:auto;-webkit-font-smoothing:antialiased;font-family:"font awesome 5 free";content:"\f122";padding-right:.5em}div.drawio{display:inline-block;position:relative}div.drawio button{position:absolute;font-size:.8em;bottom:5px;right:5px;background-color:rgba(255,166,48,.8);color:#fff;padding:.4em .5em;display:none}div.drawio:hover button{display:inline}div.drawioframe{position:fixed;height:100%;width:100%;top:0;left:0;z-index:1000;background:#000b;border:0}div.drawioframe iframe{position:absolute;height:90%;width:90%;top:5%;left:5%;z-index:1010}footer{min-height:150px}@media(max-width:991.98px){footer{min-height:200px}}@media(min-width:768px){.td-offset-anchor:target{display:block;position:relative;top:-4rem;visibility:hidden}h2[id]:before,h3[id]:before,h4[id]:before,h5[id]:before{display:block;content:" ";margin-top:-5rem;height:5rem;visibility:hidden}}body:lang(fa),body:lang(ar),body:lang(az),body:lang(dv),body:lang(he),body:lang(ku),body:lang(ur){direction:rtl;text-align:right}body:lang(fa) .m-0,body:lang(ar) .m-0,body:lang(az) .m-0,body:lang(dv) .m-0,body:lang(he) .m-0,body:lang(ku) .m-0,body:lang(ur) .m-0{margin:0!important}body:lang(fa) .mt-0,body:lang(fa) .my-0,body:lang(ar) .mt-0,body:lang(ar) .my-0,body:lang(az) .mt-0,body:lang(az) .my-0,body:lang(dv) .mt-0,body:lang(dv) .my-0,body:lang(he) .mt-0,body:lang(he) .my-0,body:lang(ku) .mt-0,body:lang(ku) .my-0,body:lang(ur) .mt-0,body:lang(ur) .my-0{margin-top:0!important}body:lang(fa) .mr-0,body:lang(fa) .mx-0,body:lang(ar) .mr-0,body:lang(ar) .mx-0,body:lang(az) .mr-0,body:lang(az) .mx-0,body:lang(dv) .mr-0,body:lang(dv) .mx-0,body:lang(he) .mr-0,body:lang(he) .mx-0,body:lang(ku) .mr-0,body:lang(ku) .mx-0,body:lang(ur) .mr-0,body:lang(ur) .mx-0{-webkit-margin-end:0!important;margin-inline-end:0!important}body:lang(fa) .mb-0,body:lang(fa) .my-0,body:lang(ar) .mb-0,body:lang(ar) .my-0,body:lang(az) .mb-0,body:lang(az) .my-0,body:lang(dv) .mb-0,body:lang(dv) .my-0,body:lang(he) .mb-0,body:lang(he) .my-0,body:lang(ku) .mb-0,body:lang(ku) .my-0,body:lang(ur) .mb-0,body:lang(ur) .my-0{margin-bottom:0!important}body:lang(fa) .ml-0,body:lang(fa) .mx-0,body:lang(ar) .ml-0,body:lang(ar) .mx-0,body:lang(az) .ml-0,body:lang(az) .mx-0,body:lang(dv) .ml-0,body:lang(dv) .mx-0,body:lang(he) .ml-0,body:lang(he) .mx-0,body:lang(ku) .ml-0,body:lang(ku) .mx-0,body:lang(ur) .ml-0,body:lang(ur) .mx-0{-webkit-margin-start:0!important;margin-inline-start:0!important}body:lang(fa) .m-1,body:lang(ar) .m-1,body:lang(az) .m-1,body:lang(dv) .m-1,body:lang(he) .m-1,body:lang(ku) .m-1,body:lang(ur) .m-1{margin:.25rem!important}body:lang(fa) .mt-1,body:lang(fa) .my-1,body:lang(ar) .mt-1,body:lang(ar) .my-1,body:lang(az) .mt-1,body:lang(az) .my-1,body:lang(dv) .mt-1,body:lang(dv) .my-1,body:lang(he) .mt-1,body:lang(he) .my-1,body:lang(ku) .mt-1,body:lang(ku) .my-1,body:lang(ur) .mt-1,body:lang(ur) .my-1{margin-top:.25rem!important}body:lang(fa) .mr-1,body:lang(fa) .mx-1,body:lang(ar) .mr-1,body:lang(ar) .mx-1,body:lang(az) .mr-1,body:lang(az) .mx-1,body:lang(dv) .mr-1,body:lang(dv) .mx-1,body:lang(he) .mr-1,body:lang(he) .mx-1,body:lang(ku) .mr-1,body:lang(ku) .mx-1,body:lang(ur) .mr-1,body:lang(ur) .mx-1{-webkit-margin-end:.25rem!important;margin-inline-end:.25rem!important}body:lang(fa) .mb-1,body:lang(fa) .my-1,body:lang(ar) .mb-1,body:lang(ar) .my-1,body:lang(az) .mb-1,body:lang(az) .my-1,body:lang(dv) .mb-1,body:lang(dv) .my-1,body:lang(he) .mb-1,body:lang(he) .my-1,body:lang(ku) .mb-1,body:lang(ku) .my-1,body:lang(ur) .mb-1,body:lang(ur) .my-1{margin-bottom:.25rem!important}body:lang(fa) .ml-1,body:lang(fa) .mx-1,body:lang(ar) .ml-1,body:lang(ar) .mx-1,body:lang(az) .ml-1,body:lang(az) .mx-1,body:lang(dv) .ml-1,body:lang(dv) .mx-1,body:lang(he) .ml-1,body:lang(he) .mx-1,body:lang(ku) .ml-1,body:lang(ku) .mx-1,body:lang(ur) .ml-1,body:lang(ur) .mx-1{-webkit-margin-start:.25rem!important;margin-inline-start:.25rem!important}body:lang(fa) .m-2,body:lang(ar) .m-2,body:lang(az) .m-2,body:lang(dv) .m-2,body:lang(he) .m-2,body:lang(ku) .m-2,body:lang(ur) .m-2{margin:.5rem!important}body:lang(fa) .mt-2,body:lang(fa) .my-2,body:lang(ar) .mt-2,body:lang(ar) .my-2,body:lang(az) .mt-2,body:lang(az) .my-2,body:lang(dv) .mt-2,body:lang(dv) .my-2,body:lang(he) .mt-2,body:lang(he) .my-2,body:lang(ku) .mt-2,body:lang(ku) .my-2,body:lang(ur) .mt-2,body:lang(ur) .my-2{margin-top:.5rem!important}body:lang(fa) .mr-2,body:lang(fa) .mx-2,body:lang(ar) .mr-2,body:lang(ar) .mx-2,body:lang(az) .mr-2,body:lang(az) .mx-2,body:lang(dv) .mr-2,body:lang(dv) .mx-2,body:lang(he) .mr-2,body:lang(he) .mx-2,body:lang(ku) .mr-2,body:lang(ku) .mx-2,body:lang(ur) .mr-2,body:lang(ur) .mx-2{-webkit-margin-end:.5rem!important;margin-inline-end:.5rem!important}body:lang(fa) .mb-2,body:lang(fa) .my-2,body:lang(ar) .mb-2,body:lang(ar) .my-2,body:lang(az) .mb-2,body:lang(az) .my-2,body:lang(dv) .mb-2,body:lang(dv) .my-2,body:lang(he) .mb-2,body:lang(he) .my-2,body:lang(ku) .mb-2,body:lang(ku) .my-2,body:lang(ur) .mb-2,body:lang(ur) .my-2{margin-bottom:.5rem!important}body:lang(fa) .ml-2,body:lang(fa) .mx-2,body:lang(ar) .ml-2,body:lang(ar) .mx-2,body:lang(az) .ml-2,body:lang(az) .mx-2,body:lang(dv) .ml-2,body:lang(dv) .mx-2,body:lang(he) .ml-2,body:lang(he) .mx-2,body:lang(ku) .ml-2,body:lang(ku) .mx-2,body:lang(ur) .ml-2,body:lang(ur) .mx-2{-webkit-margin-start:.5rem!important;margin-inline-start:.5rem!important}body:lang(fa) .m-3,body:lang(ar) .m-3,body:lang(az) .m-3,body:lang(dv) .m-3,body:lang(he) .m-3,body:lang(ku) .m-3,body:lang(ur) .m-3{margin:1rem!important}body:lang(fa) .mt-3,body:lang(fa) .my-3,body:lang(ar) .mt-3,body:lang(ar) .my-3,body:lang(az) .mt-3,body:lang(az) .my-3,body:lang(dv) .mt-3,body:lang(dv) .my-3,body:lang(he) .mt-3,body:lang(he) .my-3,body:lang(ku) .mt-3,body:lang(ku) .my-3,body:lang(ur) .mt-3,body:lang(ur) .my-3{margin-top:1rem!important}body:lang(fa) .mr-3,body:lang(fa) .mx-3,body:lang(ar) .mr-3,body:lang(ar) .mx-3,body:lang(az) .mr-3,body:lang(az) .mx-3,body:lang(dv) .mr-3,body:lang(dv) .mx-3,body:lang(he) .mr-3,body:lang(he) .mx-3,body:lang(ku) .mr-3,body:lang(ku) .mx-3,body:lang(ur) .mr-3,body:lang(ur) .mx-3{-webkit-margin-end:1rem!important;margin-inline-end:1rem!important}body:lang(fa) .mb-3,body:lang(fa) .my-3,body:lang(ar) .mb-3,body:lang(ar) .my-3,body:lang(az) .mb-3,body:lang(az) .my-3,body:lang(dv) .mb-3,body:lang(dv) .my-3,body:lang(he) .mb-3,body:lang(he) .my-3,body:lang(ku) .mb-3,body:lang(ku) .my-3,body:lang(ur) .mb-3,body:lang(ur) .my-3{margin-bottom:1rem!important}body:lang(fa) .ml-3,body:lang(fa) .mx-3,body:lang(ar) .ml-3,body:lang(ar) .mx-3,body:lang(az) .ml-3,body:lang(az) .mx-3,body:lang(dv) .ml-3,body:lang(dv) .mx-3,body:lang(he) .ml-3,body:lang(he) .mx-3,body:lang(ku) .ml-3,body:lang(ku) .mx-3,body:lang(ur) .ml-3,body:lang(ur) .mx-3{-webkit-margin-start:1rem!important;margin-inline-start:1rem!important}body:lang(fa) .m-4,body:lang(ar) .m-4,body:lang(az) .m-4,body:lang(dv) .m-4,body:lang(he) .m-4,body:lang(ku) .m-4,body:lang(ur) .m-4{margin:1.5rem!important}body:lang(fa) .mt-4,body:lang(fa) .my-4,body:lang(ar) .mt-4,body:lang(ar) .my-4,body:lang(az) .mt-4,body:lang(az) .my-4,body:lang(dv) .mt-4,body:lang(dv) .my-4,body:lang(he) .mt-4,body:lang(he) .my-4,body:lang(ku) .mt-4,body:lang(ku) .my-4,body:lang(ur) .mt-4,body:lang(ur) .my-4{margin-top:1.5rem!important}body:lang(fa) .mr-4,body:lang(fa) .mx-4,body:lang(ar) .mr-4,body:lang(ar) .mx-4,body:lang(az) .mr-4,body:lang(az) .mx-4,body:lang(dv) .mr-4,body:lang(dv) .mx-4,body:lang(he) .mr-4,body:lang(he) .mx-4,body:lang(ku) .mr-4,body:lang(ku) .mx-4,body:lang(ur) .mr-4,body:lang(ur) .mx-4{-webkit-margin-end:1.5rem!important;margin-inline-end:1.5rem!important}body:lang(fa) .mb-4,body:lang(fa) .my-4,body:lang(ar) .mb-4,body:lang(ar) .my-4,body:lang(az) .mb-4,body:lang(az) .my-4,body:lang(dv) .mb-4,body:lang(dv) .my-4,body:lang(he) .mb-4,body:lang(he) .my-4,body:lang(ku) .mb-4,body:lang(ku) .my-4,body:lang(ur) .mb-4,body:lang(ur) .my-4{margin-bottom:1.5rem!important}body:lang(fa) .ml-4,body:lang(fa) .mx-4,body:lang(ar) .ml-4,body:lang(ar) .mx-4,body:lang(az) .ml-4,body:lang(az) .mx-4,body:lang(dv) .ml-4,body:lang(dv) .mx-4,body:lang(he) .ml-4,body:lang(he) .mx-4,body:lang(ku) .ml-4,body:lang(ku) .mx-4,body:lang(ur) .ml-4,body:lang(ur) .mx-4{-webkit-margin-start:1.5rem!important;margin-inline-start:1.5rem!important}body:lang(fa) .m-5,body:lang(ar) .m-5,body:lang(az) .m-5,body:lang(dv) .m-5,body:lang(he) .m-5,body:lang(ku) .m-5,body:lang(ur) .m-5{margin:3rem!important}body:lang(fa) .mt-5,body:lang(fa) .my-5,body:lang(ar) .mt-5,body:lang(ar) .my-5,body:lang(az) .mt-5,body:lang(az) .my-5,body:lang(dv) .mt-5,body:lang(dv) .my-5,body:lang(he) .mt-5,body:lang(he) .my-5,body:lang(ku) .mt-5,body:lang(ku) .my-5,body:lang(ur) .mt-5,body:lang(ur) .my-5{margin-top:3rem!important}body:lang(fa) .mr-5,body:lang(fa) .mx-5,body:lang(ar) .mr-5,body:lang(ar) .mx-5,body:lang(az) .mr-5,body:lang(az) .mx-5,body:lang(dv) .mr-5,body:lang(dv) .mx-5,body:lang(he) .mr-5,body:lang(he) .mx-5,body:lang(ku) .mr-5,body:lang(ku) .mx-5,body:lang(ur) .mr-5,body:lang(ur) .mx-5{-webkit-margin-end:3rem!important;margin-inline-end:3rem!important}body:lang(fa) .mb-5,body:lang(fa) .my-5,body:lang(ar) .mb-5,body:lang(ar) .my-5,body:lang(az) .mb-5,body:lang(az) .my-5,body:lang(dv) .mb-5,body:lang(dv) .my-5,body:lang(he) .mb-5,body:lang(he) .my-5,body:lang(ku) .mb-5,body:lang(ku) .my-5,body:lang(ur) .mb-5,body:lang(ur) .my-5{margin-bottom:3rem!important}body:lang(fa) .ml-5,body:lang(fa) .mx-5,body:lang(ar) .ml-5,body:lang(ar) .mx-5,body:lang(az) .ml-5,body:lang(az) .mx-5,body:lang(dv) .ml-5,body:lang(dv) .mx-5,body:lang(he) .ml-5,body:lang(he) .mx-5,body:lang(ku) .ml-5,body:lang(ku) .mx-5,body:lang(ur) .ml-5,body:lang(ur) .mx-5{-webkit-margin-start:3rem!important;margin-inline-start:3rem!important}body:lang(fa) .p-0,body:lang(ar) .p-0,body:lang(az) .p-0,body:lang(dv) .p-0,body:lang(he) .p-0,body:lang(ku) .p-0,body:lang(ur) .p-0{padding:0!important}body:lang(fa) .pt-0,body:lang(fa) .py-0,body:lang(ar) .pt-0,body:lang(ar) .py-0,body:lang(az) .pt-0,body:lang(az) .py-0,body:lang(dv) .pt-0,body:lang(dv) .py-0,body:lang(he) .pt-0,body:lang(he) .py-0,body:lang(ku) .pt-0,body:lang(ku) .py-0,body:lang(ur) .pt-0,body:lang(ur) .py-0{padding-top:0!important}body:lang(fa) .pr-0,body:lang(fa) .px-0,body:lang(ar) .pr-0,body:lang(ar) .px-0,body:lang(az) .pr-0,body:lang(az) .px-0,body:lang(dv) .pr-0,body:lang(dv) .px-0,body:lang(he) .pr-0,body:lang(he) .px-0,body:lang(ku) .pr-0,body:lang(ku) .px-0,body:lang(ur) .pr-0,body:lang(ur) .px-0{-webkit-padding-end:0!important;padding-inline-end:0!important}body:lang(fa) .pb-0,body:lang(fa) .py-0,body:lang(ar) .pb-0,body:lang(ar) .py-0,body:lang(az) .pb-0,body:lang(az) .py-0,body:lang(dv) .pb-0,body:lang(dv) .py-0,body:lang(he) .pb-0,body:lang(he) .py-0,body:lang(ku) .pb-0,body:lang(ku) .py-0,body:lang(ur) .pb-0,body:lang(ur) .py-0{padding-bottom:0!important}body:lang(fa) .pl-0,body:lang(fa) .px-0,body:lang(ar) .pl-0,body:lang(ar) .px-0,body:lang(az) .pl-0,body:lang(az) .px-0,body:lang(dv) .pl-0,body:lang(dv) .px-0,body:lang(he) .pl-0,body:lang(he) .px-0,body:lang(ku) .pl-0,body:lang(ku) .px-0,body:lang(ur) .pl-0,body:lang(ur) .px-0{-webkit-padding-start:0!important;padding-inline-start:0!important}body:lang(fa) .p-1,body:lang(ar) .p-1,body:lang(az) .p-1,body:lang(dv) .p-1,body:lang(he) .p-1,body:lang(ku) .p-1,body:lang(ur) .p-1{padding:.25rem!important}body:lang(fa) .pt-1,body:lang(fa) .py-1,body:lang(ar) .pt-1,body:lang(ar) .py-1,body:lang(az) .pt-1,body:lang(az) .py-1,body:lang(dv) .pt-1,body:lang(dv) .py-1,body:lang(he) .pt-1,body:lang(he) .py-1,body:lang(ku) .pt-1,body:lang(ku) .py-1,body:lang(ur) .pt-1,body:lang(ur) .py-1{padding-top:.25rem!important}body:lang(fa) .pr-1,body:lang(fa) .px-1,body:lang(ar) .pr-1,body:lang(ar) .px-1,body:lang(az) .pr-1,body:lang(az) .px-1,body:lang(dv) .pr-1,body:lang(dv) .px-1,body:lang(he) .pr-1,body:lang(he) .px-1,body:lang(ku) .pr-1,body:lang(ku) .px-1,body:lang(ur) .pr-1,body:lang(ur) .px-1{-webkit-padding-end:.25rem!important;padding-inline-end:.25rem!important}body:lang(fa) .pb-1,body:lang(fa) .py-1,body:lang(ar) .pb-1,body:lang(ar) .py-1,body:lang(az) .pb-1,body:lang(az) .py-1,body:lang(dv) .pb-1,body:lang(dv) .py-1,body:lang(he) .pb-1,body:lang(he) .py-1,body:lang(ku) .pb-1,body:lang(ku) .py-1,body:lang(ur) .pb-1,body:lang(ur) .py-1{padding-bottom:.25rem!important}body:lang(fa) .pl-1,body:lang(fa) .px-1,body:lang(ar) .pl-1,body:lang(ar) .px-1,body:lang(az) .pl-1,body:lang(az) .px-1,body:lang(dv) .pl-1,body:lang(dv) .px-1,body:lang(he) .pl-1,body:lang(he) .px-1,body:lang(ku) .pl-1,body:lang(ku) .px-1,body:lang(ur) .pl-1,body:lang(ur) .px-1{-webkit-padding-start:.25rem!important;padding-inline-start:.25rem!important}body:lang(fa) .p-2,body:lang(ar) .p-2,body:lang(az) .p-2,body:lang(dv) .p-2,body:lang(he) .p-2,body:lang(ku) .p-2,body:lang(ur) .p-2{padding:.5rem!important}body:lang(fa) .pt-2,body:lang(fa) .py-2,body:lang(ar) .pt-2,body:lang(ar) .py-2,body:lang(az) .pt-2,body:lang(az) .py-2,body:lang(dv) .pt-2,body:lang(dv) .py-2,body:lang(he) .pt-2,body:lang(he) .py-2,body:lang(ku) .pt-2,body:lang(ku) .py-2,body:lang(ur) .pt-2,body:lang(ur) .py-2{padding-top:.5rem!important}body:lang(fa) .pr-2,body:lang(fa) .px-2,body:lang(ar) .pr-2,body:lang(ar) .px-2,body:lang(az) .pr-2,body:lang(az) .px-2,body:lang(dv) .pr-2,body:lang(dv) .px-2,body:lang(he) .pr-2,body:lang(he) .px-2,body:lang(ku) .pr-2,body:lang(ku) .px-2,body:lang(ur) .pr-2,body:lang(ur) .px-2{-webkit-padding-end:.5rem!important;padding-inline-end:.5rem!important}body:lang(fa) .pb-2,body:lang(fa) .py-2,body:lang(ar) .pb-2,body:lang(ar) .py-2,body:lang(az) .pb-2,body:lang(az) .py-2,body:lang(dv) .pb-2,body:lang(dv) .py-2,body:lang(he) .pb-2,body:lang(he) .py-2,body:lang(ku) .pb-2,body:lang(ku) .py-2,body:lang(ur) .pb-2,body:lang(ur) .py-2{padding-bottom:.5rem!important}body:lang(fa) .pl-2,body:lang(fa) .px-2,body:lang(ar) .pl-2,body:lang(ar) .px-2,body:lang(az) .pl-2,body:lang(az) .px-2,body:lang(dv) .pl-2,body:lang(dv) .px-2,body:lang(he) .pl-2,body:lang(he) .px-2,body:lang(ku) .pl-2,body:lang(ku) .px-2,body:lang(ur) .pl-2,body:lang(ur) .px-2{-webkit-padding-start:.5rem!important;padding-inline-start:.5rem!important}body:lang(fa) .p-3,body:lang(ar) .p-3,body:lang(az) .p-3,body:lang(dv) .p-3,body:lang(he) .p-3,body:lang(ku) .p-3,body:lang(ur) .p-3{padding:1rem!important}body:lang(fa) .pt-3,body:lang(fa) .py-3,body:lang(ar) .pt-3,body:lang(ar) .py-3,body:lang(az) .pt-3,body:lang(az) .py-3,body:lang(dv) .pt-3,body:lang(dv) .py-3,body:lang(he) .pt-3,body:lang(he) .py-3,body:lang(ku) .pt-3,body:lang(ku) .py-3,body:lang(ur) .pt-3,body:lang(ur) .py-3{padding-top:1rem!important}body:lang(fa) .pr-3,body:lang(fa) .px-3,body:lang(ar) .pr-3,body:lang(ar) .px-3,body:lang(az) .pr-3,body:lang(az) .px-3,body:lang(dv) .pr-3,body:lang(dv) .px-3,body:lang(he) .pr-3,body:lang(he) .px-3,body:lang(ku) .pr-3,body:lang(ku) .px-3,body:lang(ur) .pr-3,body:lang(ur) .px-3{-webkit-padding-end:1rem!important;padding-inline-end:1rem!important}body:lang(fa) .pb-3,body:lang(fa) .py-3,body:lang(ar) .pb-3,body:lang(ar) .py-3,body:lang(az) .pb-3,body:lang(az) .py-3,body:lang(dv) .pb-3,body:lang(dv) .py-3,body:lang(he) .pb-3,body:lang(he) .py-3,body:lang(ku) .pb-3,body:lang(ku) .py-3,body:lang(ur) .pb-3,body:lang(ur) .py-3{padding-bottom:1rem!important}body:lang(fa) .pl-3,body:lang(fa) .px-3,body:lang(ar) .pl-3,body:lang(ar) .px-3,body:lang(az) .pl-3,body:lang(az) .px-3,body:lang(dv) .pl-3,body:lang(dv) .px-3,body:lang(he) .pl-3,body:lang(he) .px-3,body:lang(ku) .pl-3,body:lang(ku) .px-3,body:lang(ur) .pl-3,body:lang(ur) .px-3{-webkit-padding-start:1rem!important;padding-inline-start:1rem!important}body:lang(fa) .p-4,body:lang(ar) .p-4,body:lang(az) .p-4,body:lang(dv) .p-4,body:lang(he) .p-4,body:lang(ku) .p-4,body:lang(ur) .p-4{padding:1.5rem!important}body:lang(fa) .pt-4,body:lang(fa) .py-4,body:lang(ar) .pt-4,body:lang(ar) .py-4,body:lang(az) .pt-4,body:lang(az) .py-4,body:lang(dv) .pt-4,body:lang(dv) .py-4,body:lang(he) .pt-4,body:lang(he) .py-4,body:lang(ku) .pt-4,body:lang(ku) .py-4,body:lang(ur) .pt-4,body:lang(ur) .py-4{padding-top:1.5rem!important}body:lang(fa) .pr-4,body:lang(fa) .px-4,body:lang(ar) .pr-4,body:lang(ar) .px-4,body:lang(az) .pr-4,body:lang(az) .px-4,body:lang(dv) .pr-4,body:lang(dv) .px-4,body:lang(he) .pr-4,body:lang(he) .px-4,body:lang(ku) .pr-4,body:lang(ku) .px-4,body:lang(ur) .pr-4,body:lang(ur) .px-4{-webkit-padding-end:1.5rem!important;padding-inline-end:1.5rem!important}body:lang(fa) .pb-4,body:lang(fa) .py-4,body:lang(ar) .pb-4,body:lang(ar) .py-4,body:lang(az) .pb-4,body:lang(az) .py-4,body:lang(dv) .pb-4,body:lang(dv) .py-4,body:lang(he) .pb-4,body:lang(he) .py-4,body:lang(ku) .pb-4,body:lang(ku) .py-4,body:lang(ur) .pb-4,body:lang(ur) .py-4{padding-bottom:1.5rem!important}body:lang(fa) .pl-4,body:lang(fa) .px-4,body:lang(ar) .pl-4,body:lang(ar) .px-4,body:lang(az) .pl-4,body:lang(az) .px-4,body:lang(dv) .pl-4,body:lang(dv) .px-4,body:lang(he) .pl-4,body:lang(he) .px-4,body:lang(ku) .pl-4,body:lang(ku) .px-4,body:lang(ur) .pl-4,body:lang(ur) .px-4{-webkit-padding-start:1.5rem!important;padding-inline-start:1.5rem!important}body:lang(fa) .p-5,body:lang(ar) .p-5,body:lang(az) .p-5,body:lang(dv) .p-5,body:lang(he) .p-5,body:lang(ku) .p-5,body:lang(ur) .p-5{padding:3rem!important}body:lang(fa) .pt-5,body:lang(fa) .py-5,body:lang(ar) .pt-5,body:lang(ar) .py-5,body:lang(az) .pt-5,body:lang(az) .py-5,body:lang(dv) .pt-5,body:lang(dv) .py-5,body:lang(he) .pt-5,body:lang(he) .py-5,body:lang(ku) .pt-5,body:lang(ku) .py-5,body:lang(ur) .pt-5,body:lang(ur) .py-5{padding-top:3rem!important}body:lang(fa) .pr-5,body:lang(fa) .px-5,body:lang(ar) .pr-5,body:lang(ar) .px-5,body:lang(az) .pr-5,body:lang(az) .px-5,body:lang(dv) .pr-5,body:lang(dv) .px-5,body:lang(he) .pr-5,body:lang(he) .px-5,body:lang(ku) .pr-5,body:lang(ku) .px-5,body:lang(ur) .pr-5,body:lang(ur) .px-5{-webkit-padding-end:3rem!important;padding-inline-end:3rem!important}body:lang(fa) .pb-5,body:lang(fa) .py-5,body:lang(ar) .pb-5,body:lang(ar) .py-5,body:lang(az) .pb-5,body:lang(az) .py-5,body:lang(dv) .pb-5,body:lang(dv) .py-5,body:lang(he) .pb-5,body:lang(he) .py-5,body:lang(ku) .pb-5,body:lang(ku) .py-5,body:lang(ur) .pb-5,body:lang(ur) .py-5{padding-bottom:3rem!important}body:lang(fa) .pl-5,body:lang(fa) .px-5,body:lang(ar) .pl-5,body:lang(ar) .px-5,body:lang(az) .pl-5,body:lang(az) .px-5,body:lang(dv) .pl-5,body:lang(dv) .px-5,body:lang(he) .pl-5,body:lang(he) .px-5,body:lang(ku) .pl-5,body:lang(ku) .px-5,body:lang(ur) .pl-5,body:lang(ur) .px-5{-webkit-padding-start:3rem!important;padding-inline-start:3rem!important}body:lang(fa) .m-n1,body:lang(ar) .m-n1,body:lang(az) .m-n1,body:lang(dv) .m-n1,body:lang(he) .m-n1,body:lang(ku) .m-n1,body:lang(ur) .m-n1{margin:-.25rem!important}body:lang(fa) .mt-n1,body:lang(fa) .my-n1,body:lang(ar) .mt-n1,body:lang(ar) .my-n1,body:lang(az) .mt-n1,body:lang(az) .my-n1,body:lang(dv) .mt-n1,body:lang(dv) .my-n1,body:lang(he) .mt-n1,body:lang(he) .my-n1,body:lang(ku) .mt-n1,body:lang(ku) .my-n1,body:lang(ur) .mt-n1,body:lang(ur) .my-n1{margin-top:-.25rem!important}body:lang(fa) .mr-n1,body:lang(fa) .mx-n1,body:lang(ar) .mr-n1,body:lang(ar) .mx-n1,body:lang(az) .mr-n1,body:lang(az) .mx-n1,body:lang(dv) .mr-n1,body:lang(dv) .mx-n1,body:lang(he) .mr-n1,body:lang(he) .mx-n1,body:lang(ku) .mr-n1,body:lang(ku) .mx-n1,body:lang(ur) .mr-n1,body:lang(ur) .mx-n1{margin-right:-.25rem!important}body:lang(fa) .mb-n1,body:lang(fa) .my-n1,body:lang(ar) .mb-n1,body:lang(ar) .my-n1,body:lang(az) .mb-n1,body:lang(az) .my-n1,body:lang(dv) .mb-n1,body:lang(dv) .my-n1,body:lang(he) .mb-n1,body:lang(he) .my-n1,body:lang(ku) .mb-n1,body:lang(ku) .my-n1,body:lang(ur) .mb-n1,body:lang(ur) .my-n1{margin-bottom:-.25rem!important}body:lang(fa) .ml-n1,body:lang(fa) .mx-n1,body:lang(ar) .ml-n1,body:lang(ar) .mx-n1,body:lang(az) .ml-n1,body:lang(az) .mx-n1,body:lang(dv) .ml-n1,body:lang(dv) .mx-n1,body:lang(he) .ml-n1,body:lang(he) .mx-n1,body:lang(ku) .ml-n1,body:lang(ku) .mx-n1,body:lang(ur) .ml-n1,body:lang(ur) .mx-n1{margin-left:-.25rem!important}body:lang(fa) .m-n2,body:lang(ar) .m-n2,body:lang(az) .m-n2,body:lang(dv) .m-n2,body:lang(he) .m-n2,body:lang(ku) .m-n2,body:lang(ur) .m-n2{margin:-.5rem!important}body:lang(fa) .mt-n2,body:lang(fa) .my-n2,body:lang(ar) .mt-n2,body:lang(ar) .my-n2,body:lang(az) .mt-n2,body:lang(az) .my-n2,body:lang(dv) .mt-n2,body:lang(dv) .my-n2,body:lang(he) .mt-n2,body:lang(he) .my-n2,body:lang(ku) .mt-n2,body:lang(ku) .my-n2,body:lang(ur) .mt-n2,body:lang(ur) .my-n2{margin-top:-.5rem!important}body:lang(fa) .mr-n2,body:lang(fa) .mx-n2,body:lang(ar) .mr-n2,body:lang(ar) .mx-n2,body:lang(az) .mr-n2,body:lang(az) .mx-n2,body:lang(dv) .mr-n2,body:lang(dv) .mx-n2,body:lang(he) .mr-n2,body:lang(he) .mx-n2,body:lang(ku) .mr-n2,body:lang(ku) .mx-n2,body:lang(ur) .mr-n2,body:lang(ur) .mx-n2{margin-right:-.5rem!important}body:lang(fa) .mb-n2,body:lang(fa) .my-n2,body:lang(ar) .mb-n2,body:lang(ar) .my-n2,body:lang(az) .mb-n2,body:lang(az) .my-n2,body:lang(dv) .mb-n2,body:lang(dv) .my-n2,body:lang(he) .mb-n2,body:lang(he) .my-n2,body:lang(ku) .mb-n2,body:lang(ku) .my-n2,body:lang(ur) .mb-n2,body:lang(ur) .my-n2{margin-bottom:-.5rem!important}body:lang(fa) .ml-n2,body:lang(fa) .mx-n2,body:lang(ar) .ml-n2,body:lang(ar) .mx-n2,body:lang(az) .ml-n2,body:lang(az) .mx-n2,body:lang(dv) .ml-n2,body:lang(dv) .mx-n2,body:lang(he) .ml-n2,body:lang(he) .mx-n2,body:lang(ku) .ml-n2,body:lang(ku) .mx-n2,body:lang(ur) .ml-n2,body:lang(ur) .mx-n2{margin-left:-.5rem!important}body:lang(fa) .m-n3,body:lang(ar) .m-n3,body:lang(az) .m-n3,body:lang(dv) .m-n3,body:lang(he) .m-n3,body:lang(ku) .m-n3,body:lang(ur) .m-n3{margin:-1rem!important}body:lang(fa) .mt-n3,body:lang(fa) .my-n3,body:lang(ar) .mt-n3,body:lang(ar) .my-n3,body:lang(az) .mt-n3,body:lang(az) .my-n3,body:lang(dv) .mt-n3,body:lang(dv) .my-n3,body:lang(he) .mt-n3,body:lang(he) .my-n3,body:lang(ku) .mt-n3,body:lang(ku) .my-n3,body:lang(ur) .mt-n3,body:lang(ur) .my-n3{margin-top:-1rem!important}body:lang(fa) .mr-n3,body:lang(fa) .mx-n3,body:lang(ar) .mr-n3,body:lang(ar) .mx-n3,body:lang(az) .mr-n3,body:lang(az) .mx-n3,body:lang(dv) .mr-n3,body:lang(dv) .mx-n3,body:lang(he) .mr-n3,body:lang(he) .mx-n3,body:lang(ku) .mr-n3,body:lang(ku) .mx-n3,body:lang(ur) .mr-n3,body:lang(ur) .mx-n3{margin-right:-1rem!important}body:lang(fa) .mb-n3,body:lang(fa) .my-n3,body:lang(ar) .mb-n3,body:lang(ar) .my-n3,body:lang(az) .mb-n3,body:lang(az) .my-n3,body:lang(dv) .mb-n3,body:lang(dv) .my-n3,body:lang(he) .mb-n3,body:lang(he) .my-n3,body:lang(ku) .mb-n3,body:lang(ku) .my-n3,body:lang(ur) .mb-n3,body:lang(ur) .my-n3{margin-bottom:-1rem!important}body:lang(fa) .ml-n3,body:lang(fa) .mx-n3,body:lang(ar) .ml-n3,body:lang(ar) .mx-n3,body:lang(az) .ml-n3,body:lang(az) .mx-n3,body:lang(dv) .ml-n3,body:lang(dv) .mx-n3,body:lang(he) .ml-n3,body:lang(he) .mx-n3,body:lang(ku) .ml-n3,body:lang(ku) .mx-n3,body:lang(ur) .ml-n3,body:lang(ur) .mx-n3{margin-left:-1rem!important}body:lang(fa) .m-n4,body:lang(ar) .m-n4,body:lang(az) .m-n4,body:lang(dv) .m-n4,body:lang(he) .m-n4,body:lang(ku) .m-n4,body:lang(ur) .m-n4{margin:-1.5rem!important}body:lang(fa) .mt-n4,body:lang(fa) .my-n4,body:lang(ar) .mt-n4,body:lang(ar) .my-n4,body:lang(az) .mt-n4,body:lang(az) .my-n4,body:lang(dv) .mt-n4,body:lang(dv) .my-n4,body:lang(he) .mt-n4,body:lang(he) .my-n4,body:lang(ku) .mt-n4,body:lang(ku) .my-n4,body:lang(ur) .mt-n4,body:lang(ur) .my-n4{margin-top:-1.5rem!important}body:lang(fa) .mr-n4,body:lang(fa) .mx-n4,body:lang(ar) .mr-n4,body:lang(ar) .mx-n4,body:lang(az) .mr-n4,body:lang(az) .mx-n4,body:lang(dv) .mr-n4,body:lang(dv) .mx-n4,body:lang(he) .mr-n4,body:lang(he) .mx-n4,body:lang(ku) .mr-n4,body:lang(ku) .mx-n4,body:lang(ur) .mr-n4,body:lang(ur) .mx-n4{margin-right:-1.5rem!important}body:lang(fa) .mb-n4,body:lang(fa) .my-n4,body:lang(ar) .mb-n4,body:lang(ar) .my-n4,body:lang(az) .mb-n4,body:lang(az) .my-n4,body:lang(dv) .mb-n4,body:lang(dv) .my-n4,body:lang(he) .mb-n4,body:lang(he) .my-n4,body:lang(ku) .mb-n4,body:lang(ku) .my-n4,body:lang(ur) .mb-n4,body:lang(ur) .my-n4{margin-bottom:-1.5rem!important}body:lang(fa) .ml-n4,body:lang(fa) .mx-n4,body:lang(ar) .ml-n4,body:lang(ar) .mx-n4,body:lang(az) .ml-n4,body:lang(az) .mx-n4,body:lang(dv) .ml-n4,body:lang(dv) .mx-n4,body:lang(he) .ml-n4,body:lang(he) .mx-n4,body:lang(ku) .ml-n4,body:lang(ku) .mx-n4,body:lang(ur) .ml-n4,body:lang(ur) .mx-n4{margin-left:-1.5rem!important}body:lang(fa) .m-n5,body:lang(ar) .m-n5,body:lang(az) .m-n5,body:lang(dv) .m-n5,body:lang(he) .m-n5,body:lang(ku) .m-n5,body:lang(ur) .m-n5{margin:-3rem!important}body:lang(fa) .mt-n5,body:lang(fa) .my-n5,body:lang(ar) .mt-n5,body:lang(ar) .my-n5,body:lang(az) .mt-n5,body:lang(az) .my-n5,body:lang(dv) .mt-n5,body:lang(dv) .my-n5,body:lang(he) .mt-n5,body:lang(he) .my-n5,body:lang(ku) .mt-n5,body:lang(ku) .my-n5,body:lang(ur) .mt-n5,body:lang(ur) .my-n5{margin-top:-3rem!important}body:lang(fa) .mr-n5,body:lang(fa) .mx-n5,body:lang(ar) .mr-n5,body:lang(ar) .mx-n5,body:lang(az) .mr-n5,body:lang(az) .mx-n5,body:lang(dv) .mr-n5,body:lang(dv) .mx-n5,body:lang(he) .mr-n5,body:lang(he) .mx-n5,body:lang(ku) .mr-n5,body:lang(ku) .mx-n5,body:lang(ur) .mr-n5,body:lang(ur) .mx-n5{margin-right:-3rem!important}body:lang(fa) .mb-n5,body:lang(fa) .my-n5,body:lang(ar) .mb-n5,body:lang(ar) .my-n5,body:lang(az) .mb-n5,body:lang(az) .my-n5,body:lang(dv) .mb-n5,body:lang(dv) .my-n5,body:lang(he) .mb-n5,body:lang(he) .my-n5,body:lang(ku) .mb-n5,body:lang(ku) .my-n5,body:lang(ur) .mb-n5,body:lang(ur) .my-n5{margin-bottom:-3rem!important}body:lang(fa) .ml-n5,body:lang(fa) .mx-n5,body:lang(ar) .ml-n5,body:lang(ar) .mx-n5,body:lang(az) .ml-n5,body:lang(az) .mx-n5,body:lang(dv) .ml-n5,body:lang(dv) .mx-n5,body:lang(he) .ml-n5,body:lang(he) .mx-n5,body:lang(ku) .ml-n5,body:lang(ku) .mx-n5,body:lang(ur) .ml-n5,body:lang(ur) .mx-n5{margin-left:-3rem!important}body:lang(fa) .m-auto,body:lang(ar) .m-auto,body:lang(az) .m-auto,body:lang(dv) .m-auto,body:lang(he) .m-auto,body:lang(ku) .m-auto,body:lang(ur) .m-auto{margin:auto!important}body:lang(fa) .mt-auto,body:lang(fa) .my-auto,body:lang(ar) .mt-auto,body:lang(ar) .my-auto,body:lang(az) .mt-auto,body:lang(az) .my-auto,body:lang(dv) .mt-auto,body:lang(dv) .my-auto,body:lang(he) .mt-auto,body:lang(he) .my-auto,body:lang(ku) .mt-auto,body:lang(ku) .my-auto,body:lang(ur) .mt-auto,body:lang(ur) .my-auto{margin-top:auto!important}body:lang(fa) .mr-auto,body:lang(fa) .mx-auto,body:lang(ar) .mr-auto,body:lang(ar) .mx-auto,body:lang(az) .mr-auto,body:lang(az) .mx-auto,body:lang(dv) .mr-auto,body:lang(dv) .mx-auto,body:lang(he) .mr-auto,body:lang(he) .mx-auto,body:lang(ku) .mr-auto,body:lang(ku) .mx-auto,body:lang(ur) .mr-auto,body:lang(ur) .mx-auto{margin-right:auto!important}body:lang(fa) .mb-auto,body:lang(fa) .my-auto,body:lang(ar) .mb-auto,body:lang(ar) .my-auto,body:lang(az) .mb-auto,body:lang(az) .my-auto,body:lang(dv) .mb-auto,body:lang(dv) .my-auto,body:lang(he) .mb-auto,body:lang(he) .my-auto,body:lang(ku) .mb-auto,body:lang(ku) .my-auto,body:lang(ur) .mb-auto,body:lang(ur) .my-auto{margin-bottom:auto!important}body:lang(fa) .ml-auto,body:lang(fa) .mx-auto,body:lang(ar) .ml-auto,body:lang(ar) .mx-auto,body:lang(az) .ml-auto,body:lang(az) .mx-auto,body:lang(dv) .ml-auto,body:lang(dv) .mx-auto,body:lang(he) .ml-auto,body:lang(he) .mx-auto,body:lang(ku) .ml-auto,body:lang(ku) .mx-auto,body:lang(ur) .ml-auto,body:lang(ur) .mx-auto{margin-left:auto!important}@media(min-width:576px){body:lang(fa) .m-sm-0,body:lang(ar) .m-sm-0,body:lang(az) .m-sm-0,body:lang(dv) .m-sm-0,body:lang(he) .m-sm-0,body:lang(ku) .m-sm-0,body:lang(ur) .m-sm-0{margin:0!important}body:lang(fa) .mt-sm-0,body:lang(fa) .my-sm-0,body:lang(ar) .mt-sm-0,body:lang(ar) .my-sm-0,body:lang(az) .mt-sm-0,body:lang(az) .my-sm-0,body:lang(dv) .mt-sm-0,body:lang(dv) .my-sm-0,body:lang(he) .mt-sm-0,body:lang(he) .my-sm-0,body:lang(ku) .mt-sm-0,body:lang(ku) .my-sm-0,body:lang(ur) .mt-sm-0,body:lang(ur) .my-sm-0{margin-top:0!important}body:lang(fa) .mr-sm-0,body:lang(fa) .mx-sm-0,body:lang(ar) .mr-sm-0,body:lang(ar) .mx-sm-0,body:lang(az) .mr-sm-0,body:lang(az) .mx-sm-0,body:lang(dv) .mr-sm-0,body:lang(dv) .mx-sm-0,body:lang(he) .mr-sm-0,body:lang(he) .mx-sm-0,body:lang(ku) .mr-sm-0,body:lang(ku) .mx-sm-0,body:lang(ur) .mr-sm-0,body:lang(ur) .mx-sm-0{-webkit-margin-end:0!important;margin-inline-end:0!important}body:lang(fa) .mb-sm-0,body:lang(fa) .my-sm-0,body:lang(ar) .mb-sm-0,body:lang(ar) .my-sm-0,body:lang(az) .mb-sm-0,body:lang(az) .my-sm-0,body:lang(dv) .mb-sm-0,body:lang(dv) .my-sm-0,body:lang(he) .mb-sm-0,body:lang(he) .my-sm-0,body:lang(ku) .mb-sm-0,body:lang(ku) .my-sm-0,body:lang(ur) .mb-sm-0,body:lang(ur) .my-sm-0{margin-bottom:0!important}body:lang(fa) .ml-sm-0,body:lang(fa) .mx-sm-0,body:lang(ar) .ml-sm-0,body:lang(ar) .mx-sm-0,body:lang(az) .ml-sm-0,body:lang(az) .mx-sm-0,body:lang(dv) .ml-sm-0,body:lang(dv) .mx-sm-0,body:lang(he) .ml-sm-0,body:lang(he) .mx-sm-0,body:lang(ku) .ml-sm-0,body:lang(ku) .mx-sm-0,body:lang(ur) .ml-sm-0,body:lang(ur) .mx-sm-0{-webkit-margin-start:0!important;margin-inline-start:0!important}body:lang(fa) .m-sm-1,body:lang(ar) .m-sm-1,body:lang(az) .m-sm-1,body:lang(dv) .m-sm-1,body:lang(he) .m-sm-1,body:lang(ku) .m-sm-1,body:lang(ur) .m-sm-1{margin:.25rem!important}body:lang(fa) .mt-sm-1,body:lang(fa) .my-sm-1,body:lang(ar) .mt-sm-1,body:lang(ar) .my-sm-1,body:lang(az) .mt-sm-1,body:lang(az) .my-sm-1,body:lang(dv) .mt-sm-1,body:lang(dv) .my-sm-1,body:lang(he) .mt-sm-1,body:lang(he) .my-sm-1,body:lang(ku) .mt-sm-1,body:lang(ku) .my-sm-1,body:lang(ur) .mt-sm-1,body:lang(ur) .my-sm-1{margin-top:.25rem!important}body:lang(fa) .mr-sm-1,body:lang(fa) .mx-sm-1,body:lang(ar) .mr-sm-1,body:lang(ar) .mx-sm-1,body:lang(az) .mr-sm-1,body:lang(az) .mx-sm-1,body:lang(dv) .mr-sm-1,body:lang(dv) .mx-sm-1,body:lang(he) .mr-sm-1,body:lang(he) .mx-sm-1,body:lang(ku) .mr-sm-1,body:lang(ku) .mx-sm-1,body:lang(ur) .mr-sm-1,body:lang(ur) .mx-sm-1{-webkit-margin-end:.25rem!important;margin-inline-end:.25rem!important}body:lang(fa) .mb-sm-1,body:lang(fa) .my-sm-1,body:lang(ar) .mb-sm-1,body:lang(ar) .my-sm-1,body:lang(az) .mb-sm-1,body:lang(az) .my-sm-1,body:lang(dv) .mb-sm-1,body:lang(dv) .my-sm-1,body:lang(he) .mb-sm-1,body:lang(he) .my-sm-1,body:lang(ku) .mb-sm-1,body:lang(ku) .my-sm-1,body:lang(ur) .mb-sm-1,body:lang(ur) .my-sm-1{margin-bottom:.25rem!important}body:lang(fa) .ml-sm-1,body:lang(fa) .mx-sm-1,body:lang(ar) .ml-sm-1,body:lang(ar) .mx-sm-1,body:lang(az) .ml-sm-1,body:lang(az) .mx-sm-1,body:lang(dv) .ml-sm-1,body:lang(dv) .mx-sm-1,body:lang(he) .ml-sm-1,body:lang(he) .mx-sm-1,body:lang(ku) .ml-sm-1,body:lang(ku) .mx-sm-1,body:lang(ur) .ml-sm-1,body:lang(ur) .mx-sm-1{-webkit-margin-start:.25rem!important;margin-inline-start:.25rem!important}body:lang(fa) .m-sm-2,body:lang(ar) .m-sm-2,body:lang(az) .m-sm-2,body:lang(dv) .m-sm-2,body:lang(he) .m-sm-2,body:lang(ku) .m-sm-2,body:lang(ur) .m-sm-2{margin:.5rem!important}body:lang(fa) .mt-sm-2,body:lang(fa) .my-sm-2,body:lang(ar) .mt-sm-2,body:lang(ar) .my-sm-2,body:lang(az) .mt-sm-2,body:lang(az) .my-sm-2,body:lang(dv) .mt-sm-2,body:lang(dv) .my-sm-2,body:lang(he) .mt-sm-2,body:lang(he) .my-sm-2,body:lang(ku) .mt-sm-2,body:lang(ku) .my-sm-2,body:lang(ur) .mt-sm-2,body:lang(ur) .my-sm-2{margin-top:.5rem!important}body:lang(fa) .mr-sm-2,body:lang(fa) .mx-sm-2,body:lang(ar) .mr-sm-2,body:lang(ar) .mx-sm-2,body:lang(az) .mr-sm-2,body:lang(az) .mx-sm-2,body:lang(dv) .mr-sm-2,body:lang(dv) .mx-sm-2,body:lang(he) .mr-sm-2,body:lang(he) .mx-sm-2,body:lang(ku) .mr-sm-2,body:lang(ku) .mx-sm-2,body:lang(ur) .mr-sm-2,body:lang(ur) .mx-sm-2{-webkit-margin-end:.5rem!important;margin-inline-end:.5rem!important}body:lang(fa) .mb-sm-2,body:lang(fa) .my-sm-2,body:lang(ar) .mb-sm-2,body:lang(ar) .my-sm-2,body:lang(az) .mb-sm-2,body:lang(az) .my-sm-2,body:lang(dv) .mb-sm-2,body:lang(dv) .my-sm-2,body:lang(he) .mb-sm-2,body:lang(he) .my-sm-2,body:lang(ku) .mb-sm-2,body:lang(ku) .my-sm-2,body:lang(ur) .mb-sm-2,body:lang(ur) .my-sm-2{margin-bottom:.5rem!important}body:lang(fa) .ml-sm-2,body:lang(fa) .mx-sm-2,body:lang(ar) .ml-sm-2,body:lang(ar) .mx-sm-2,body:lang(az) .ml-sm-2,body:lang(az) .mx-sm-2,body:lang(dv) .ml-sm-2,body:lang(dv) .mx-sm-2,body:lang(he) .ml-sm-2,body:lang(he) .mx-sm-2,body:lang(ku) .ml-sm-2,body:lang(ku) .mx-sm-2,body:lang(ur) .ml-sm-2,body:lang(ur) .mx-sm-2{-webkit-margin-start:.5rem!important;margin-inline-start:.5rem!important}body:lang(fa) .m-sm-3,body:lang(ar) .m-sm-3,body:lang(az) .m-sm-3,body:lang(dv) .m-sm-3,body:lang(he) .m-sm-3,body:lang(ku) .m-sm-3,body:lang(ur) .m-sm-3{margin:1rem!important}body:lang(fa) .mt-sm-3,body:lang(fa) .my-sm-3,body:lang(ar) .mt-sm-3,body:lang(ar) .my-sm-3,body:lang(az) .mt-sm-3,body:lang(az) .my-sm-3,body:lang(dv) .mt-sm-3,body:lang(dv) .my-sm-3,body:lang(he) .mt-sm-3,body:lang(he) .my-sm-3,body:lang(ku) .mt-sm-3,body:lang(ku) .my-sm-3,body:lang(ur) .mt-sm-3,body:lang(ur) .my-sm-3{margin-top:1rem!important}body:lang(fa) .mr-sm-3,body:lang(fa) .mx-sm-3,body:lang(ar) .mr-sm-3,body:lang(ar) .mx-sm-3,body:lang(az) .mr-sm-3,body:lang(az) .mx-sm-3,body:lang(dv) .mr-sm-3,body:lang(dv) .mx-sm-3,body:lang(he) .mr-sm-3,body:lang(he) .mx-sm-3,body:lang(ku) .mr-sm-3,body:lang(ku) .mx-sm-3,body:lang(ur) .mr-sm-3,body:lang(ur) .mx-sm-3{-webkit-margin-end:1rem!important;margin-inline-end:1rem!important}body:lang(fa) .mb-sm-3,body:lang(fa) .my-sm-3,body:lang(ar) .mb-sm-3,body:lang(ar) .my-sm-3,body:lang(az) .mb-sm-3,body:lang(az) .my-sm-3,body:lang(dv) .mb-sm-3,body:lang(dv) .my-sm-3,body:lang(he) .mb-sm-3,body:lang(he) .my-sm-3,body:lang(ku) .mb-sm-3,body:lang(ku) .my-sm-3,body:lang(ur) .mb-sm-3,body:lang(ur) .my-sm-3{margin-bottom:1rem!important}body:lang(fa) .ml-sm-3,body:lang(fa) .mx-sm-3,body:lang(ar) .ml-sm-3,body:lang(ar) .mx-sm-3,body:lang(az) .ml-sm-3,body:lang(az) .mx-sm-3,body:lang(dv) .ml-sm-3,body:lang(dv) .mx-sm-3,body:lang(he) .ml-sm-3,body:lang(he) .mx-sm-3,body:lang(ku) .ml-sm-3,body:lang(ku) .mx-sm-3,body:lang(ur) .ml-sm-3,body:lang(ur) .mx-sm-3{-webkit-margin-start:1rem!important;margin-inline-start:1rem!important}body:lang(fa) .m-sm-4,body:lang(ar) .m-sm-4,body:lang(az) .m-sm-4,body:lang(dv) .m-sm-4,body:lang(he) .m-sm-4,body:lang(ku) .m-sm-4,body:lang(ur) .m-sm-4{margin:1.5rem!important}body:lang(fa) .mt-sm-4,body:lang(fa) .my-sm-4,body:lang(ar) .mt-sm-4,body:lang(ar) .my-sm-4,body:lang(az) .mt-sm-4,body:lang(az) .my-sm-4,body:lang(dv) .mt-sm-4,body:lang(dv) .my-sm-4,body:lang(he) .mt-sm-4,body:lang(he) .my-sm-4,body:lang(ku) .mt-sm-4,body:lang(ku) .my-sm-4,body:lang(ur) .mt-sm-4,body:lang(ur) .my-sm-4{margin-top:1.5rem!important}body:lang(fa) .mr-sm-4,body:lang(fa) .mx-sm-4,body:lang(ar) .mr-sm-4,body:lang(ar) .mx-sm-4,body:lang(az) .mr-sm-4,body:lang(az) .mx-sm-4,body:lang(dv) .mr-sm-4,body:lang(dv) .mx-sm-4,body:lang(he) .mr-sm-4,body:lang(he) .mx-sm-4,body:lang(ku) .mr-sm-4,body:lang(ku) .mx-sm-4,body:lang(ur) .mr-sm-4,body:lang(ur) .mx-sm-4{-webkit-margin-end:1.5rem!important;margin-inline-end:1.5rem!important}body:lang(fa) .mb-sm-4,body:lang(fa) .my-sm-4,body:lang(ar) .mb-sm-4,body:lang(ar) .my-sm-4,body:lang(az) .mb-sm-4,body:lang(az) .my-sm-4,body:lang(dv) .mb-sm-4,body:lang(dv) .my-sm-4,body:lang(he) .mb-sm-4,body:lang(he) .my-sm-4,body:lang(ku) .mb-sm-4,body:lang(ku) .my-sm-4,body:lang(ur) .mb-sm-4,body:lang(ur) .my-sm-4{margin-bottom:1.5rem!important}body:lang(fa) .ml-sm-4,body:lang(fa) .mx-sm-4,body:lang(ar) .ml-sm-4,body:lang(ar) .mx-sm-4,body:lang(az) .ml-sm-4,body:lang(az) .mx-sm-4,body:lang(dv) .ml-sm-4,body:lang(dv) .mx-sm-4,body:lang(he) .ml-sm-4,body:lang(he) .mx-sm-4,body:lang(ku) .ml-sm-4,body:lang(ku) .mx-sm-4,body:lang(ur) .ml-sm-4,body:lang(ur) .mx-sm-4{-webkit-margin-start:1.5rem!important;margin-inline-start:1.5rem!important}body:lang(fa) .m-sm-5,body:lang(ar) .m-sm-5,body:lang(az) .m-sm-5,body:lang(dv) .m-sm-5,body:lang(he) .m-sm-5,body:lang(ku) .m-sm-5,body:lang(ur) .m-sm-5{margin:3rem!important}body:lang(fa) .mt-sm-5,body:lang(fa) .my-sm-5,body:lang(ar) .mt-sm-5,body:lang(ar) .my-sm-5,body:lang(az) .mt-sm-5,body:lang(az) .my-sm-5,body:lang(dv) .mt-sm-5,body:lang(dv) .my-sm-5,body:lang(he) .mt-sm-5,body:lang(he) .my-sm-5,body:lang(ku) .mt-sm-5,body:lang(ku) .my-sm-5,body:lang(ur) .mt-sm-5,body:lang(ur) .my-sm-5{margin-top:3rem!important}body:lang(fa) .mr-sm-5,body:lang(fa) .mx-sm-5,body:lang(ar) .mr-sm-5,body:lang(ar) .mx-sm-5,body:lang(az) .mr-sm-5,body:lang(az) .mx-sm-5,body:lang(dv) .mr-sm-5,body:lang(dv) .mx-sm-5,body:lang(he) .mr-sm-5,body:lang(he) .mx-sm-5,body:lang(ku) .mr-sm-5,body:lang(ku) .mx-sm-5,body:lang(ur) .mr-sm-5,body:lang(ur) .mx-sm-5{-webkit-margin-end:3rem!important;margin-inline-end:3rem!important}body:lang(fa) .mb-sm-5,body:lang(fa) .my-sm-5,body:lang(ar) .mb-sm-5,body:lang(ar) .my-sm-5,body:lang(az) .mb-sm-5,body:lang(az) .my-sm-5,body:lang(dv) .mb-sm-5,body:lang(dv) .my-sm-5,body:lang(he) .mb-sm-5,body:lang(he) .my-sm-5,body:lang(ku) .mb-sm-5,body:lang(ku) .my-sm-5,body:lang(ur) .mb-sm-5,body:lang(ur) .my-sm-5{margin-bottom:3rem!important}body:lang(fa) .ml-sm-5,body:lang(fa) .mx-sm-5,body:lang(ar) .ml-sm-5,body:lang(ar) .mx-sm-5,body:lang(az) .ml-sm-5,body:lang(az) .mx-sm-5,body:lang(dv) .ml-sm-5,body:lang(dv) .mx-sm-5,body:lang(he) .ml-sm-5,body:lang(he) .mx-sm-5,body:lang(ku) .ml-sm-5,body:lang(ku) .mx-sm-5,body:lang(ur) .ml-sm-5,body:lang(ur) .mx-sm-5{-webkit-margin-start:3rem!important;margin-inline-start:3rem!important}body:lang(fa) .p-sm-0,body:lang(ar) .p-sm-0,body:lang(az) .p-sm-0,body:lang(dv) .p-sm-0,body:lang(he) .p-sm-0,body:lang(ku) .p-sm-0,body:lang(ur) .p-sm-0{padding:0!important}body:lang(fa) .pt-sm-0,body:lang(fa) .py-sm-0,body:lang(ar) .pt-sm-0,body:lang(ar) .py-sm-0,body:lang(az) .pt-sm-0,body:lang(az) .py-sm-0,body:lang(dv) .pt-sm-0,body:lang(dv) .py-sm-0,body:lang(he) .pt-sm-0,body:lang(he) .py-sm-0,body:lang(ku) .pt-sm-0,body:lang(ku) .py-sm-0,body:lang(ur) .pt-sm-0,body:lang(ur) .py-sm-0{padding-top:0!important}body:lang(fa) .pr-sm-0,body:lang(fa) .px-sm-0,body:lang(ar) .pr-sm-0,body:lang(ar) .px-sm-0,body:lang(az) .pr-sm-0,body:lang(az) .px-sm-0,body:lang(dv) .pr-sm-0,body:lang(dv) .px-sm-0,body:lang(he) .pr-sm-0,body:lang(he) .px-sm-0,body:lang(ku) .pr-sm-0,body:lang(ku) .px-sm-0,body:lang(ur) .pr-sm-0,body:lang(ur) .px-sm-0{-webkit-padding-end:0!important;padding-inline-end:0!important}body:lang(fa) .pb-sm-0,body:lang(fa) .py-sm-0,body:lang(ar) .pb-sm-0,body:lang(ar) .py-sm-0,body:lang(az) .pb-sm-0,body:lang(az) .py-sm-0,body:lang(dv) .pb-sm-0,body:lang(dv) .py-sm-0,body:lang(he) .pb-sm-0,body:lang(he) .py-sm-0,body:lang(ku) .pb-sm-0,body:lang(ku) .py-sm-0,body:lang(ur) .pb-sm-0,body:lang(ur) .py-sm-0{padding-bottom:0!important}body:lang(fa) .pl-sm-0,body:lang(fa) .px-sm-0,body:lang(ar) .pl-sm-0,body:lang(ar) .px-sm-0,body:lang(az) .pl-sm-0,body:lang(az) .px-sm-0,body:lang(dv) .pl-sm-0,body:lang(dv) .px-sm-0,body:lang(he) .pl-sm-0,body:lang(he) .px-sm-0,body:lang(ku) .pl-sm-0,body:lang(ku) .px-sm-0,body:lang(ur) .pl-sm-0,body:lang(ur) .px-sm-0{-webkit-padding-start:0!important;padding-inline-start:0!important}body:lang(fa) .p-sm-1,body:lang(ar) .p-sm-1,body:lang(az) .p-sm-1,body:lang(dv) .p-sm-1,body:lang(he) .p-sm-1,body:lang(ku) .p-sm-1,body:lang(ur) .p-sm-1{padding:.25rem!important}body:lang(fa) .pt-sm-1,body:lang(fa) .py-sm-1,body:lang(ar) .pt-sm-1,body:lang(ar) .py-sm-1,body:lang(az) .pt-sm-1,body:lang(az) .py-sm-1,body:lang(dv) .pt-sm-1,body:lang(dv) .py-sm-1,body:lang(he) .pt-sm-1,body:lang(he) .py-sm-1,body:lang(ku) .pt-sm-1,body:lang(ku) .py-sm-1,body:lang(ur) .pt-sm-1,body:lang(ur) .py-sm-1{padding-top:.25rem!important}body:lang(fa) .pr-sm-1,body:lang(fa) .px-sm-1,body:lang(ar) .pr-sm-1,body:lang(ar) .px-sm-1,body:lang(az) .pr-sm-1,body:lang(az) .px-sm-1,body:lang(dv) .pr-sm-1,body:lang(dv) .px-sm-1,body:lang(he) .pr-sm-1,body:lang(he) .px-sm-1,body:lang(ku) .pr-sm-1,body:lang(ku) .px-sm-1,body:lang(ur) .pr-sm-1,body:lang(ur) .px-sm-1{-webkit-padding-end:.25rem!important;padding-inline-end:.25rem!important}body:lang(fa) .pb-sm-1,body:lang(fa) .py-sm-1,body:lang(ar) .pb-sm-1,body:lang(ar) .py-sm-1,body:lang(az) .pb-sm-1,body:lang(az) .py-sm-1,body:lang(dv) .pb-sm-1,body:lang(dv) .py-sm-1,body:lang(he) .pb-sm-1,body:lang(he) .py-sm-1,body:lang(ku) .pb-sm-1,body:lang(ku) .py-sm-1,body:lang(ur) .pb-sm-1,body:lang(ur) .py-sm-1{padding-bottom:.25rem!important}body:lang(fa) .pl-sm-1,body:lang(fa) .px-sm-1,body:lang(ar) .pl-sm-1,body:lang(ar) .px-sm-1,body:lang(az) .pl-sm-1,body:lang(az) .px-sm-1,body:lang(dv) .pl-sm-1,body:lang(dv) .px-sm-1,body:lang(he) .pl-sm-1,body:lang(he) .px-sm-1,body:lang(ku) .pl-sm-1,body:lang(ku) .px-sm-1,body:lang(ur) .pl-sm-1,body:lang(ur) .px-sm-1{-webkit-padding-start:.25rem!important;padding-inline-start:.25rem!important}body:lang(fa) .p-sm-2,body:lang(ar) .p-sm-2,body:lang(az) .p-sm-2,body:lang(dv) .p-sm-2,body:lang(he) .p-sm-2,body:lang(ku) .p-sm-2,body:lang(ur) .p-sm-2{padding:.5rem!important}body:lang(fa) .pt-sm-2,body:lang(fa) .py-sm-2,body:lang(ar) .pt-sm-2,body:lang(ar) .py-sm-2,body:lang(az) .pt-sm-2,body:lang(az) .py-sm-2,body:lang(dv) .pt-sm-2,body:lang(dv) .py-sm-2,body:lang(he) .pt-sm-2,body:lang(he) .py-sm-2,body:lang(ku) .pt-sm-2,body:lang(ku) .py-sm-2,body:lang(ur) .pt-sm-2,body:lang(ur) .py-sm-2{padding-top:.5rem!important}body:lang(fa) .pr-sm-2,body:lang(fa) .px-sm-2,body:lang(ar) .pr-sm-2,body:lang(ar) .px-sm-2,body:lang(az) .pr-sm-2,body:lang(az) .px-sm-2,body:lang(dv) .pr-sm-2,body:lang(dv) .px-sm-2,body:lang(he) .pr-sm-2,body:lang(he) .px-sm-2,body:lang(ku) .pr-sm-2,body:lang(ku) .px-sm-2,body:lang(ur) .pr-sm-2,body:lang(ur) .px-sm-2{-webkit-padding-end:.5rem!important;padding-inline-end:.5rem!important}body:lang(fa) .pb-sm-2,body:lang(fa) .py-sm-2,body:lang(ar) .pb-sm-2,body:lang(ar) .py-sm-2,body:lang(az) .pb-sm-2,body:lang(az) .py-sm-2,body:lang(dv) .pb-sm-2,body:lang(dv) .py-sm-2,body:lang(he) .pb-sm-2,body:lang(he) .py-sm-2,body:lang(ku) .pb-sm-2,body:lang(ku) .py-sm-2,body:lang(ur) .pb-sm-2,body:lang(ur) .py-sm-2{padding-bottom:.5rem!important}body:lang(fa) .pl-sm-2,body:lang(fa) .px-sm-2,body:lang(ar) .pl-sm-2,body:lang(ar) .px-sm-2,body:lang(az) .pl-sm-2,body:lang(az) .px-sm-2,body:lang(dv) .pl-sm-2,body:lang(dv) .px-sm-2,body:lang(he) .pl-sm-2,body:lang(he) .px-sm-2,body:lang(ku) .pl-sm-2,body:lang(ku) .px-sm-2,body:lang(ur) .pl-sm-2,body:lang(ur) .px-sm-2{-webkit-padding-start:.5rem!important;padding-inline-start:.5rem!important}body:lang(fa) .p-sm-3,body:lang(ar) .p-sm-3,body:lang(az) .p-sm-3,body:lang(dv) .p-sm-3,body:lang(he) .p-sm-3,body:lang(ku) .p-sm-3,body:lang(ur) .p-sm-3{padding:1rem!important}body:lang(fa) .pt-sm-3,body:lang(fa) .py-sm-3,body:lang(ar) .pt-sm-3,body:lang(ar) .py-sm-3,body:lang(az) .pt-sm-3,body:lang(az) .py-sm-3,body:lang(dv) .pt-sm-3,body:lang(dv) .py-sm-3,body:lang(he) .pt-sm-3,body:lang(he) .py-sm-3,body:lang(ku) .pt-sm-3,body:lang(ku) .py-sm-3,body:lang(ur) .pt-sm-3,body:lang(ur) .py-sm-3{padding-top:1rem!important}body:lang(fa) .pr-sm-3,body:lang(fa) .px-sm-3,body:lang(ar) .pr-sm-3,body:lang(ar) .px-sm-3,body:lang(az) .pr-sm-3,body:lang(az) .px-sm-3,body:lang(dv) .pr-sm-3,body:lang(dv) .px-sm-3,body:lang(he) .pr-sm-3,body:lang(he) .px-sm-3,body:lang(ku) .pr-sm-3,body:lang(ku) .px-sm-3,body:lang(ur) .pr-sm-3,body:lang(ur) .px-sm-3{-webkit-padding-end:1rem!important;padding-inline-end:1rem!important}body:lang(fa) .pb-sm-3,body:lang(fa) .py-sm-3,body:lang(ar) .pb-sm-3,body:lang(ar) .py-sm-3,body:lang(az) .pb-sm-3,body:lang(az) .py-sm-3,body:lang(dv) .pb-sm-3,body:lang(dv) .py-sm-3,body:lang(he) .pb-sm-3,body:lang(he) .py-sm-3,body:lang(ku) .pb-sm-3,body:lang(ku) .py-sm-3,body:lang(ur) .pb-sm-3,body:lang(ur) .py-sm-3{padding-bottom:1rem!important}body:lang(fa) .pl-sm-3,body:lang(fa) .px-sm-3,body:lang(ar) .pl-sm-3,body:lang(ar) .px-sm-3,body:lang(az) .pl-sm-3,body:lang(az) .px-sm-3,body:lang(dv) .pl-sm-3,body:lang(dv) .px-sm-3,body:lang(he) .pl-sm-3,body:lang(he) .px-sm-3,body:lang(ku) .pl-sm-3,body:lang(ku) .px-sm-3,body:lang(ur) .pl-sm-3,body:lang(ur) .px-sm-3{-webkit-padding-start:1rem!important;padding-inline-start:1rem!important}body:lang(fa) .p-sm-4,body:lang(ar) .p-sm-4,body:lang(az) .p-sm-4,body:lang(dv) .p-sm-4,body:lang(he) .p-sm-4,body:lang(ku) .p-sm-4,body:lang(ur) .p-sm-4{padding:1.5rem!important}body:lang(fa) .pt-sm-4,body:lang(fa) .py-sm-4,body:lang(ar) .pt-sm-4,body:lang(ar) .py-sm-4,body:lang(az) .pt-sm-4,body:lang(az) .py-sm-4,body:lang(dv) .pt-sm-4,body:lang(dv) .py-sm-4,body:lang(he) .pt-sm-4,body:lang(he) .py-sm-4,body:lang(ku) .pt-sm-4,body:lang(ku) .py-sm-4,body:lang(ur) .pt-sm-4,body:lang(ur) .py-sm-4{padding-top:1.5rem!important}body:lang(fa) .pr-sm-4,body:lang(fa) .px-sm-4,body:lang(ar) .pr-sm-4,body:lang(ar) .px-sm-4,body:lang(az) .pr-sm-4,body:lang(az) .px-sm-4,body:lang(dv) .pr-sm-4,body:lang(dv) .px-sm-4,body:lang(he) .pr-sm-4,body:lang(he) .px-sm-4,body:lang(ku) .pr-sm-4,body:lang(ku) .px-sm-4,body:lang(ur) .pr-sm-4,body:lang(ur) .px-sm-4{-webkit-padding-end:1.5rem!important;padding-inline-end:1.5rem!important}body:lang(fa) .pb-sm-4,body:lang(fa) .py-sm-4,body:lang(ar) .pb-sm-4,body:lang(ar) .py-sm-4,body:lang(az) .pb-sm-4,body:lang(az) .py-sm-4,body:lang(dv) .pb-sm-4,body:lang(dv) .py-sm-4,body:lang(he) .pb-sm-4,body:lang(he) .py-sm-4,body:lang(ku) .pb-sm-4,body:lang(ku) .py-sm-4,body:lang(ur) .pb-sm-4,body:lang(ur) .py-sm-4{padding-bottom:1.5rem!important}body:lang(fa) .pl-sm-4,body:lang(fa) .px-sm-4,body:lang(ar) .pl-sm-4,body:lang(ar) .px-sm-4,body:lang(az) .pl-sm-4,body:lang(az) .px-sm-4,body:lang(dv) .pl-sm-4,body:lang(dv) .px-sm-4,body:lang(he) .pl-sm-4,body:lang(he) .px-sm-4,body:lang(ku) .pl-sm-4,body:lang(ku) .px-sm-4,body:lang(ur) .pl-sm-4,body:lang(ur) .px-sm-4{-webkit-padding-start:1.5rem!important;padding-inline-start:1.5rem!important}body:lang(fa) .p-sm-5,body:lang(ar) .p-sm-5,body:lang(az) .p-sm-5,body:lang(dv) .p-sm-5,body:lang(he) .p-sm-5,body:lang(ku) .p-sm-5,body:lang(ur) .p-sm-5{padding:3rem!important}body:lang(fa) .pt-sm-5,body:lang(fa) .py-sm-5,body:lang(ar) .pt-sm-5,body:lang(ar) .py-sm-5,body:lang(az) .pt-sm-5,body:lang(az) .py-sm-5,body:lang(dv) .pt-sm-5,body:lang(dv) .py-sm-5,body:lang(he) .pt-sm-5,body:lang(he) .py-sm-5,body:lang(ku) .pt-sm-5,body:lang(ku) .py-sm-5,body:lang(ur) .pt-sm-5,body:lang(ur) .py-sm-5{padding-top:3rem!important}body:lang(fa) .pr-sm-5,body:lang(fa) .px-sm-5,body:lang(ar) .pr-sm-5,body:lang(ar) .px-sm-5,body:lang(az) .pr-sm-5,body:lang(az) .px-sm-5,body:lang(dv) .pr-sm-5,body:lang(dv) .px-sm-5,body:lang(he) .pr-sm-5,body:lang(he) .px-sm-5,body:lang(ku) .pr-sm-5,body:lang(ku) .px-sm-5,body:lang(ur) .pr-sm-5,body:lang(ur) .px-sm-5{-webkit-padding-end:3rem!important;padding-inline-end:3rem!important}body:lang(fa) .pb-sm-5,body:lang(fa) .py-sm-5,body:lang(ar) .pb-sm-5,body:lang(ar) .py-sm-5,body:lang(az) .pb-sm-5,body:lang(az) .py-sm-5,body:lang(dv) .pb-sm-5,body:lang(dv) .py-sm-5,body:lang(he) .pb-sm-5,body:lang(he) .py-sm-5,body:lang(ku) .pb-sm-5,body:lang(ku) .py-sm-5,body:lang(ur) .pb-sm-5,body:lang(ur) .py-sm-5{padding-bottom:3rem!important}body:lang(fa) .pl-sm-5,body:lang(fa) .px-sm-5,body:lang(ar) .pl-sm-5,body:lang(ar) .px-sm-5,body:lang(az) .pl-sm-5,body:lang(az) .px-sm-5,body:lang(dv) .pl-sm-5,body:lang(dv) .px-sm-5,body:lang(he) .pl-sm-5,body:lang(he) .px-sm-5,body:lang(ku) .pl-sm-5,body:lang(ku) .px-sm-5,body:lang(ur) .pl-sm-5,body:lang(ur) .px-sm-5{-webkit-padding-start:3rem!important;padding-inline-start:3rem!important}body:lang(fa) .m-sm-n1,body:lang(ar) .m-sm-n1,body:lang(az) .m-sm-n1,body:lang(dv) .m-sm-n1,body:lang(he) .m-sm-n1,body:lang(ku) .m-sm-n1,body:lang(ur) .m-sm-n1{margin:-.25rem!important}body:lang(fa) .mt-sm-n1,body:lang(fa) .my-sm-n1,body:lang(ar) .mt-sm-n1,body:lang(ar) .my-sm-n1,body:lang(az) .mt-sm-n1,body:lang(az) .my-sm-n1,body:lang(dv) .mt-sm-n1,body:lang(dv) .my-sm-n1,body:lang(he) .mt-sm-n1,body:lang(he) .my-sm-n1,body:lang(ku) .mt-sm-n1,body:lang(ku) .my-sm-n1,body:lang(ur) .mt-sm-n1,body:lang(ur) .my-sm-n1{margin-top:-.25rem!important}body:lang(fa) .mr-sm-n1,body:lang(fa) .mx-sm-n1,body:lang(ar) .mr-sm-n1,body:lang(ar) .mx-sm-n1,body:lang(az) .mr-sm-n1,body:lang(az) .mx-sm-n1,body:lang(dv) .mr-sm-n1,body:lang(dv) .mx-sm-n1,body:lang(he) .mr-sm-n1,body:lang(he) .mx-sm-n1,body:lang(ku) .mr-sm-n1,body:lang(ku) .mx-sm-n1,body:lang(ur) .mr-sm-n1,body:lang(ur) .mx-sm-n1{margin-right:-.25rem!important}body:lang(fa) .mb-sm-n1,body:lang(fa) .my-sm-n1,body:lang(ar) .mb-sm-n1,body:lang(ar) .my-sm-n1,body:lang(az) .mb-sm-n1,body:lang(az) .my-sm-n1,body:lang(dv) .mb-sm-n1,body:lang(dv) .my-sm-n1,body:lang(he) .mb-sm-n1,body:lang(he) .my-sm-n1,body:lang(ku) .mb-sm-n1,body:lang(ku) .my-sm-n1,body:lang(ur) .mb-sm-n1,body:lang(ur) .my-sm-n1{margin-bottom:-.25rem!important}body:lang(fa) .ml-sm-n1,body:lang(fa) .mx-sm-n1,body:lang(ar) .ml-sm-n1,body:lang(ar) .mx-sm-n1,body:lang(az) .ml-sm-n1,body:lang(az) .mx-sm-n1,body:lang(dv) .ml-sm-n1,body:lang(dv) .mx-sm-n1,body:lang(he) .ml-sm-n1,body:lang(he) .mx-sm-n1,body:lang(ku) .ml-sm-n1,body:lang(ku) .mx-sm-n1,body:lang(ur) .ml-sm-n1,body:lang(ur) .mx-sm-n1{margin-left:-.25rem!important}body:lang(fa) .m-sm-n2,body:lang(ar) .m-sm-n2,body:lang(az) .m-sm-n2,body:lang(dv) .m-sm-n2,body:lang(he) .m-sm-n2,body:lang(ku) .m-sm-n2,body:lang(ur) .m-sm-n2{margin:-.5rem!important}body:lang(fa) .mt-sm-n2,body:lang(fa) .my-sm-n2,body:lang(ar) .mt-sm-n2,body:lang(ar) .my-sm-n2,body:lang(az) .mt-sm-n2,body:lang(az) .my-sm-n2,body:lang(dv) .mt-sm-n2,body:lang(dv) .my-sm-n2,body:lang(he) .mt-sm-n2,body:lang(he) .my-sm-n2,body:lang(ku) .mt-sm-n2,body:lang(ku) .my-sm-n2,body:lang(ur) .mt-sm-n2,body:lang(ur) .my-sm-n2{margin-top:-.5rem!important}body:lang(fa) .mr-sm-n2,body:lang(fa) .mx-sm-n2,body:lang(ar) .mr-sm-n2,body:lang(ar) .mx-sm-n2,body:lang(az) .mr-sm-n2,body:lang(az) .mx-sm-n2,body:lang(dv) .mr-sm-n2,body:lang(dv) .mx-sm-n2,body:lang(he) .mr-sm-n2,body:lang(he) .mx-sm-n2,body:lang(ku) .mr-sm-n2,body:lang(ku) .mx-sm-n2,body:lang(ur) .mr-sm-n2,body:lang(ur) .mx-sm-n2{margin-right:-.5rem!important}body:lang(fa) .mb-sm-n2,body:lang(fa) .my-sm-n2,body:lang(ar) .mb-sm-n2,body:lang(ar) .my-sm-n2,body:lang(az) .mb-sm-n2,body:lang(az) .my-sm-n2,body:lang(dv) .mb-sm-n2,body:lang(dv) .my-sm-n2,body:lang(he) .mb-sm-n2,body:lang(he) .my-sm-n2,body:lang(ku) .mb-sm-n2,body:lang(ku) .my-sm-n2,body:lang(ur) .mb-sm-n2,body:lang(ur) .my-sm-n2{margin-bottom:-.5rem!important}body:lang(fa) .ml-sm-n2,body:lang(fa) .mx-sm-n2,body:lang(ar) .ml-sm-n2,body:lang(ar) .mx-sm-n2,body:lang(az) .ml-sm-n2,body:lang(az) .mx-sm-n2,body:lang(dv) .ml-sm-n2,body:lang(dv) .mx-sm-n2,body:lang(he) .ml-sm-n2,body:lang(he) .mx-sm-n2,body:lang(ku) .ml-sm-n2,body:lang(ku) .mx-sm-n2,body:lang(ur) .ml-sm-n2,body:lang(ur) .mx-sm-n2{margin-left:-.5rem!important}body:lang(fa) .m-sm-n3,body:lang(ar) .m-sm-n3,body:lang(az) .m-sm-n3,body:lang(dv) .m-sm-n3,body:lang(he) .m-sm-n3,body:lang(ku) .m-sm-n3,body:lang(ur) .m-sm-n3{margin:-1rem!important}body:lang(fa) .mt-sm-n3,body:lang(fa) .my-sm-n3,body:lang(ar) .mt-sm-n3,body:lang(ar) .my-sm-n3,body:lang(az) .mt-sm-n3,body:lang(az) .my-sm-n3,body:lang(dv) .mt-sm-n3,body:lang(dv) .my-sm-n3,body:lang(he) .mt-sm-n3,body:lang(he) .my-sm-n3,body:lang(ku) .mt-sm-n3,body:lang(ku) .my-sm-n3,body:lang(ur) .mt-sm-n3,body:lang(ur) .my-sm-n3{margin-top:-1rem!important}body:lang(fa) .mr-sm-n3,body:lang(fa) .mx-sm-n3,body:lang(ar) .mr-sm-n3,body:lang(ar) .mx-sm-n3,body:lang(az) .mr-sm-n3,body:lang(az) .mx-sm-n3,body:lang(dv) .mr-sm-n3,body:lang(dv) .mx-sm-n3,body:lang(he) .mr-sm-n3,body:lang(he) .mx-sm-n3,body:lang(ku) .mr-sm-n3,body:lang(ku) .mx-sm-n3,body:lang(ur) .mr-sm-n3,body:lang(ur) .mx-sm-n3{margin-right:-1rem!important}body:lang(fa) .mb-sm-n3,body:lang(fa) .my-sm-n3,body:lang(ar) .mb-sm-n3,body:lang(ar) .my-sm-n3,body:lang(az) .mb-sm-n3,body:lang(az) .my-sm-n3,body:lang(dv) .mb-sm-n3,body:lang(dv) .my-sm-n3,body:lang(he) .mb-sm-n3,body:lang(he) .my-sm-n3,body:lang(ku) .mb-sm-n3,body:lang(ku) .my-sm-n3,body:lang(ur) .mb-sm-n3,body:lang(ur) .my-sm-n3{margin-bottom:-1rem!important}body:lang(fa) .ml-sm-n3,body:lang(fa) .mx-sm-n3,body:lang(ar) .ml-sm-n3,body:lang(ar) .mx-sm-n3,body:lang(az) .ml-sm-n3,body:lang(az) .mx-sm-n3,body:lang(dv) .ml-sm-n3,body:lang(dv) .mx-sm-n3,body:lang(he) .ml-sm-n3,body:lang(he) .mx-sm-n3,body:lang(ku) .ml-sm-n3,body:lang(ku) .mx-sm-n3,body:lang(ur) .ml-sm-n3,body:lang(ur) .mx-sm-n3{margin-left:-1rem!important}body:lang(fa) .m-sm-n4,body:lang(ar) .m-sm-n4,body:lang(az) .m-sm-n4,body:lang(dv) .m-sm-n4,body:lang(he) .m-sm-n4,body:lang(ku) .m-sm-n4,body:lang(ur) .m-sm-n4{margin:-1.5rem!important}body:lang(fa) .mt-sm-n4,body:lang(fa) .my-sm-n4,body:lang(ar) .mt-sm-n4,body:lang(ar) .my-sm-n4,body:lang(az) .mt-sm-n4,body:lang(az) .my-sm-n4,body:lang(dv) .mt-sm-n4,body:lang(dv) .my-sm-n4,body:lang(he) .mt-sm-n4,body:lang(he) .my-sm-n4,body:lang(ku) .mt-sm-n4,body:lang(ku) .my-sm-n4,body:lang(ur) .mt-sm-n4,body:lang(ur) .my-sm-n4{margin-top:-1.5rem!important}body:lang(fa) .mr-sm-n4,body:lang(fa) .mx-sm-n4,body:lang(ar) .mr-sm-n4,body:lang(ar) .mx-sm-n4,body:lang(az) .mr-sm-n4,body:lang(az) .mx-sm-n4,body:lang(dv) .mr-sm-n4,body:lang(dv) .mx-sm-n4,body:lang(he) .mr-sm-n4,body:lang(he) .mx-sm-n4,body:lang(ku) .mr-sm-n4,body:lang(ku) .mx-sm-n4,body:lang(ur) .mr-sm-n4,body:lang(ur) .mx-sm-n4{margin-right:-1.5rem!important}body:lang(fa) .mb-sm-n4,body:lang(fa) .my-sm-n4,body:lang(ar) .mb-sm-n4,body:lang(ar) .my-sm-n4,body:lang(az) .mb-sm-n4,body:lang(az) .my-sm-n4,body:lang(dv) .mb-sm-n4,body:lang(dv) .my-sm-n4,body:lang(he) .mb-sm-n4,body:lang(he) .my-sm-n4,body:lang(ku) .mb-sm-n4,body:lang(ku) .my-sm-n4,body:lang(ur) .mb-sm-n4,body:lang(ur) .my-sm-n4{margin-bottom:-1.5rem!important}body:lang(fa) .ml-sm-n4,body:lang(fa) .mx-sm-n4,body:lang(ar) .ml-sm-n4,body:lang(ar) .mx-sm-n4,body:lang(az) .ml-sm-n4,body:lang(az) .mx-sm-n4,body:lang(dv) .ml-sm-n4,body:lang(dv) .mx-sm-n4,body:lang(he) .ml-sm-n4,body:lang(he) .mx-sm-n4,body:lang(ku) .ml-sm-n4,body:lang(ku) .mx-sm-n4,body:lang(ur) .ml-sm-n4,body:lang(ur) .mx-sm-n4{margin-left:-1.5rem!important}body:lang(fa) .m-sm-n5,body:lang(ar) .m-sm-n5,body:lang(az) .m-sm-n5,body:lang(dv) .m-sm-n5,body:lang(he) .m-sm-n5,body:lang(ku) .m-sm-n5,body:lang(ur) .m-sm-n5{margin:-3rem!important}body:lang(fa) .mt-sm-n5,body:lang(fa) .my-sm-n5,body:lang(ar) .mt-sm-n5,body:lang(ar) .my-sm-n5,body:lang(az) .mt-sm-n5,body:lang(az) .my-sm-n5,body:lang(dv) .mt-sm-n5,body:lang(dv) .my-sm-n5,body:lang(he) .mt-sm-n5,body:lang(he) .my-sm-n5,body:lang(ku) .mt-sm-n5,body:lang(ku) .my-sm-n5,body:lang(ur) .mt-sm-n5,body:lang(ur) .my-sm-n5{margin-top:-3rem!important}body:lang(fa) .mr-sm-n5,body:lang(fa) .mx-sm-n5,body:lang(ar) .mr-sm-n5,body:lang(ar) .mx-sm-n5,body:lang(az) .mr-sm-n5,body:lang(az) .mx-sm-n5,body:lang(dv) .mr-sm-n5,body:lang(dv) .mx-sm-n5,body:lang(he) .mr-sm-n5,body:lang(he) .mx-sm-n5,body:lang(ku) .mr-sm-n5,body:lang(ku) .mx-sm-n5,body:lang(ur) .mr-sm-n5,body:lang(ur) .mx-sm-n5{margin-right:-3rem!important}body:lang(fa) .mb-sm-n5,body:lang(fa) .my-sm-n5,body:lang(ar) .mb-sm-n5,body:lang(ar) .my-sm-n5,body:lang(az) .mb-sm-n5,body:lang(az) .my-sm-n5,body:lang(dv) .mb-sm-n5,body:lang(dv) .my-sm-n5,body:lang(he) .mb-sm-n5,body:lang(he) .my-sm-n5,body:lang(ku) .mb-sm-n5,body:lang(ku) .my-sm-n5,body:lang(ur) .mb-sm-n5,body:lang(ur) .my-sm-n5{margin-bottom:-3rem!important}body:lang(fa) .ml-sm-n5,body:lang(fa) .mx-sm-n5,body:lang(ar) .ml-sm-n5,body:lang(ar) .mx-sm-n5,body:lang(az) .ml-sm-n5,body:lang(az) .mx-sm-n5,body:lang(dv) .ml-sm-n5,body:lang(dv) .mx-sm-n5,body:lang(he) .ml-sm-n5,body:lang(he) .mx-sm-n5,body:lang(ku) .ml-sm-n5,body:lang(ku) .mx-sm-n5,body:lang(ur) .ml-sm-n5,body:lang(ur) .mx-sm-n5{margin-left:-3rem!important}body:lang(fa) .m-sm-auto,body:lang(ar) .m-sm-auto,body:lang(az) .m-sm-auto,body:lang(dv) .m-sm-auto,body:lang(he) .m-sm-auto,body:lang(ku) .m-sm-auto,body:lang(ur) .m-sm-auto{margin:auto!important}body:lang(fa) .mt-sm-auto,body:lang(fa) .my-sm-auto,body:lang(ar) .mt-sm-auto,body:lang(ar) .my-sm-auto,body:lang(az) .mt-sm-auto,body:lang(az) .my-sm-auto,body:lang(dv) .mt-sm-auto,body:lang(dv) .my-sm-auto,body:lang(he) .mt-sm-auto,body:lang(he) .my-sm-auto,body:lang(ku) .mt-sm-auto,body:lang(ku) .my-sm-auto,body:lang(ur) .mt-sm-auto,body:lang(ur) .my-sm-auto{margin-top:auto!important}body:lang(fa) .mr-sm-auto,body:lang(fa) .mx-sm-auto,body:lang(ar) .mr-sm-auto,body:lang(ar) .mx-sm-auto,body:lang(az) .mr-sm-auto,body:lang(az) .mx-sm-auto,body:lang(dv) .mr-sm-auto,body:lang(dv) .mx-sm-auto,body:lang(he) .mr-sm-auto,body:lang(he) .mx-sm-auto,body:lang(ku) .mr-sm-auto,body:lang(ku) .mx-sm-auto,body:lang(ur) .mr-sm-auto,body:lang(ur) .mx-sm-auto{margin-right:auto!important}body:lang(fa) .mb-sm-auto,body:lang(fa) .my-sm-auto,body:lang(ar) .mb-sm-auto,body:lang(ar) .my-sm-auto,body:lang(az) .mb-sm-auto,body:lang(az) .my-sm-auto,body:lang(dv) .mb-sm-auto,body:lang(dv) .my-sm-auto,body:lang(he) .mb-sm-auto,body:lang(he) .my-sm-auto,body:lang(ku) .mb-sm-auto,body:lang(ku) .my-sm-auto,body:lang(ur) .mb-sm-auto,body:lang(ur) .my-sm-auto{margin-bottom:auto!important}body:lang(fa) .ml-sm-auto,body:lang(fa) .mx-sm-auto,body:lang(ar) .ml-sm-auto,body:lang(ar) .mx-sm-auto,body:lang(az) .ml-sm-auto,body:lang(az) .mx-sm-auto,body:lang(dv) .ml-sm-auto,body:lang(dv) .mx-sm-auto,body:lang(he) .ml-sm-auto,body:lang(he) .mx-sm-auto,body:lang(ku) .ml-sm-auto,body:lang(ku) .mx-sm-auto,body:lang(ur) .ml-sm-auto,body:lang(ur) .mx-sm-auto{margin-left:auto!important}}@media(min-width:768px){body:lang(fa) .m-md-0,body:lang(ar) .m-md-0,body:lang(az) .m-md-0,body:lang(dv) .m-md-0,body:lang(he) .m-md-0,body:lang(ku) .m-md-0,body:lang(ur) .m-md-0{margin:0!important}body:lang(fa) .mt-md-0,body:lang(fa) .my-md-0,body:lang(ar) .mt-md-0,body:lang(ar) .my-md-0,body:lang(az) .mt-md-0,body:lang(az) .my-md-0,body:lang(dv) .mt-md-0,body:lang(dv) .my-md-0,body:lang(he) .mt-md-0,body:lang(he) .my-md-0,body:lang(ku) .mt-md-0,body:lang(ku) .my-md-0,body:lang(ur) .mt-md-0,body:lang(ur) .my-md-0{margin-top:0!important}body:lang(fa) .mr-md-0,body:lang(fa) .mx-md-0,body:lang(ar) .mr-md-0,body:lang(ar) .mx-md-0,body:lang(az) .mr-md-0,body:lang(az) .mx-md-0,body:lang(dv) .mr-md-0,body:lang(dv) .mx-md-0,body:lang(he) .mr-md-0,body:lang(he) .mx-md-0,body:lang(ku) .mr-md-0,body:lang(ku) .mx-md-0,body:lang(ur) .mr-md-0,body:lang(ur) .mx-md-0{-webkit-margin-end:0!important;margin-inline-end:0!important}body:lang(fa) .mb-md-0,body:lang(fa) .my-md-0,body:lang(ar) .mb-md-0,body:lang(ar) .my-md-0,body:lang(az) .mb-md-0,body:lang(az) .my-md-0,body:lang(dv) .mb-md-0,body:lang(dv) .my-md-0,body:lang(he) .mb-md-0,body:lang(he) .my-md-0,body:lang(ku) .mb-md-0,body:lang(ku) .my-md-0,body:lang(ur) .mb-md-0,body:lang(ur) .my-md-0{margin-bottom:0!important}body:lang(fa) .ml-md-0,body:lang(fa) .mx-md-0,body:lang(ar) .ml-md-0,body:lang(ar) .mx-md-0,body:lang(az) .ml-md-0,body:lang(az) .mx-md-0,body:lang(dv) .ml-md-0,body:lang(dv) .mx-md-0,body:lang(he) .ml-md-0,body:lang(he) .mx-md-0,body:lang(ku) .ml-md-0,body:lang(ku) .mx-md-0,body:lang(ur) .ml-md-0,body:lang(ur) .mx-md-0{-webkit-margin-start:0!important;margin-inline-start:0!important}body:lang(fa) .m-md-1,body:lang(ar) .m-md-1,body:lang(az) .m-md-1,body:lang(dv) .m-md-1,body:lang(he) .m-md-1,body:lang(ku) .m-md-1,body:lang(ur) .m-md-1{margin:.25rem!important}body:lang(fa) .mt-md-1,body:lang(fa) .my-md-1,body:lang(ar) .mt-md-1,body:lang(ar) .my-md-1,body:lang(az) .mt-md-1,body:lang(az) .my-md-1,body:lang(dv) .mt-md-1,body:lang(dv) .my-md-1,body:lang(he) .mt-md-1,body:lang(he) .my-md-1,body:lang(ku) .mt-md-1,body:lang(ku) .my-md-1,body:lang(ur) .mt-md-1,body:lang(ur) .my-md-1{margin-top:.25rem!important}body:lang(fa) .mr-md-1,body:lang(fa) .mx-md-1,body:lang(ar) .mr-md-1,body:lang(ar) .mx-md-1,body:lang(az) .mr-md-1,body:lang(az) .mx-md-1,body:lang(dv) .mr-md-1,body:lang(dv) .mx-md-1,body:lang(he) .mr-md-1,body:lang(he) .mx-md-1,body:lang(ku) .mr-md-1,body:lang(ku) .mx-md-1,body:lang(ur) .mr-md-1,body:lang(ur) .mx-md-1{-webkit-margin-end:.25rem!important;margin-inline-end:.25rem!important}body:lang(fa) .mb-md-1,body:lang(fa) .my-md-1,body:lang(ar) .mb-md-1,body:lang(ar) .my-md-1,body:lang(az) .mb-md-1,body:lang(az) .my-md-1,body:lang(dv) .mb-md-1,body:lang(dv) .my-md-1,body:lang(he) .mb-md-1,body:lang(he) .my-md-1,body:lang(ku) .mb-md-1,body:lang(ku) .my-md-1,body:lang(ur) .mb-md-1,body:lang(ur) .my-md-1{margin-bottom:.25rem!important}body:lang(fa) .ml-md-1,body:lang(fa) .mx-md-1,body:lang(ar) .ml-md-1,body:lang(ar) .mx-md-1,body:lang(az) .ml-md-1,body:lang(az) .mx-md-1,body:lang(dv) .ml-md-1,body:lang(dv) .mx-md-1,body:lang(he) .ml-md-1,body:lang(he) .mx-md-1,body:lang(ku) .ml-md-1,body:lang(ku) .mx-md-1,body:lang(ur) .ml-md-1,body:lang(ur) .mx-md-1{-webkit-margin-start:.25rem!important;margin-inline-start:.25rem!important}body:lang(fa) .m-md-2,body:lang(ar) .m-md-2,body:lang(az) .m-md-2,body:lang(dv) .m-md-2,body:lang(he) .m-md-2,body:lang(ku) .m-md-2,body:lang(ur) .m-md-2{margin:.5rem!important}body:lang(fa) .mt-md-2,body:lang(fa) .my-md-2,body:lang(ar) .mt-md-2,body:lang(ar) .my-md-2,body:lang(az) .mt-md-2,body:lang(az) .my-md-2,body:lang(dv) .mt-md-2,body:lang(dv) .my-md-2,body:lang(he) .mt-md-2,body:lang(he) .my-md-2,body:lang(ku) .mt-md-2,body:lang(ku) .my-md-2,body:lang(ur) .mt-md-2,body:lang(ur) .my-md-2{margin-top:.5rem!important}body:lang(fa) .mr-md-2,body:lang(fa) .mx-md-2,body:lang(ar) .mr-md-2,body:lang(ar) .mx-md-2,body:lang(az) .mr-md-2,body:lang(az) .mx-md-2,body:lang(dv) .mr-md-2,body:lang(dv) .mx-md-2,body:lang(he) .mr-md-2,body:lang(he) .mx-md-2,body:lang(ku) .mr-md-2,body:lang(ku) .mx-md-2,body:lang(ur) .mr-md-2,body:lang(ur) .mx-md-2{-webkit-margin-end:.5rem!important;margin-inline-end:.5rem!important}body:lang(fa) .mb-md-2,body:lang(fa) .my-md-2,body:lang(ar) .mb-md-2,body:lang(ar) .my-md-2,body:lang(az) .mb-md-2,body:lang(az) .my-md-2,body:lang(dv) .mb-md-2,body:lang(dv) .my-md-2,body:lang(he) .mb-md-2,body:lang(he) .my-md-2,body:lang(ku) .mb-md-2,body:lang(ku) .my-md-2,body:lang(ur) .mb-md-2,body:lang(ur) .my-md-2{margin-bottom:.5rem!important}body:lang(fa) .ml-md-2,body:lang(fa) .mx-md-2,body:lang(ar) .ml-md-2,body:lang(ar) .mx-md-2,body:lang(az) .ml-md-2,body:lang(az) .mx-md-2,body:lang(dv) .ml-md-2,body:lang(dv) .mx-md-2,body:lang(he) .ml-md-2,body:lang(he) .mx-md-2,body:lang(ku) .ml-md-2,body:lang(ku) .mx-md-2,body:lang(ur) .ml-md-2,body:lang(ur) .mx-md-2{-webkit-margin-start:.5rem!important;margin-inline-start:.5rem!important}body:lang(fa) .m-md-3,body:lang(ar) .m-md-3,body:lang(az) .m-md-3,body:lang(dv) .m-md-3,body:lang(he) .m-md-3,body:lang(ku) .m-md-3,body:lang(ur) .m-md-3{margin:1rem!important}body:lang(fa) .mt-md-3,body:lang(fa) .my-md-3,body:lang(ar) .mt-md-3,body:lang(ar) .my-md-3,body:lang(az) .mt-md-3,body:lang(az) .my-md-3,body:lang(dv) .mt-md-3,body:lang(dv) .my-md-3,body:lang(he) .mt-md-3,body:lang(he) .my-md-3,body:lang(ku) .mt-md-3,body:lang(ku) .my-md-3,body:lang(ur) .mt-md-3,body:lang(ur) .my-md-3{margin-top:1rem!important}body:lang(fa) .mr-md-3,body:lang(fa) .mx-md-3,body:lang(ar) .mr-md-3,body:lang(ar) .mx-md-3,body:lang(az) .mr-md-3,body:lang(az) .mx-md-3,body:lang(dv) .mr-md-3,body:lang(dv) .mx-md-3,body:lang(he) .mr-md-3,body:lang(he) .mx-md-3,body:lang(ku) .mr-md-3,body:lang(ku) .mx-md-3,body:lang(ur) .mr-md-3,body:lang(ur) .mx-md-3{-webkit-margin-end:1rem!important;margin-inline-end:1rem!important}body:lang(fa) .mb-md-3,body:lang(fa) .my-md-3,body:lang(ar) .mb-md-3,body:lang(ar) .my-md-3,body:lang(az) .mb-md-3,body:lang(az) .my-md-3,body:lang(dv) .mb-md-3,body:lang(dv) .my-md-3,body:lang(he) .mb-md-3,body:lang(he) .my-md-3,body:lang(ku) .mb-md-3,body:lang(ku) .my-md-3,body:lang(ur) .mb-md-3,body:lang(ur) .my-md-3{margin-bottom:1rem!important}body:lang(fa) .ml-md-3,body:lang(fa) .mx-md-3,body:lang(ar) .ml-md-3,body:lang(ar) .mx-md-3,body:lang(az) .ml-md-3,body:lang(az) .mx-md-3,body:lang(dv) .ml-md-3,body:lang(dv) .mx-md-3,body:lang(he) .ml-md-3,body:lang(he) .mx-md-3,body:lang(ku) .ml-md-3,body:lang(ku) .mx-md-3,body:lang(ur) .ml-md-3,body:lang(ur) .mx-md-3{-webkit-margin-start:1rem!important;margin-inline-start:1rem!important}body:lang(fa) .m-md-4,body:lang(ar) .m-md-4,body:lang(az) .m-md-4,body:lang(dv) .m-md-4,body:lang(he) .m-md-4,body:lang(ku) .m-md-4,body:lang(ur) .m-md-4{margin:1.5rem!important}body:lang(fa) .mt-md-4,body:lang(fa) .my-md-4,body:lang(ar) .mt-md-4,body:lang(ar) .my-md-4,body:lang(az) .mt-md-4,body:lang(az) .my-md-4,body:lang(dv) .mt-md-4,body:lang(dv) .my-md-4,body:lang(he) .mt-md-4,body:lang(he) .my-md-4,body:lang(ku) .mt-md-4,body:lang(ku) .my-md-4,body:lang(ur) .mt-md-4,body:lang(ur) .my-md-4{margin-top:1.5rem!important}body:lang(fa) .mr-md-4,body:lang(fa) .mx-md-4,body:lang(ar) .mr-md-4,body:lang(ar) .mx-md-4,body:lang(az) .mr-md-4,body:lang(az) .mx-md-4,body:lang(dv) .mr-md-4,body:lang(dv) .mx-md-4,body:lang(he) .mr-md-4,body:lang(he) .mx-md-4,body:lang(ku) .mr-md-4,body:lang(ku) .mx-md-4,body:lang(ur) .mr-md-4,body:lang(ur) .mx-md-4{-webkit-margin-end:1.5rem!important;margin-inline-end:1.5rem!important}body:lang(fa) .mb-md-4,body:lang(fa) .my-md-4,body:lang(ar) .mb-md-4,body:lang(ar) .my-md-4,body:lang(az) .mb-md-4,body:lang(az) .my-md-4,body:lang(dv) .mb-md-4,body:lang(dv) .my-md-4,body:lang(he) .mb-md-4,body:lang(he) .my-md-4,body:lang(ku) .mb-md-4,body:lang(ku) .my-md-4,body:lang(ur) .mb-md-4,body:lang(ur) .my-md-4{margin-bottom:1.5rem!important}body:lang(fa) .ml-md-4,body:lang(fa) .mx-md-4,body:lang(ar) .ml-md-4,body:lang(ar) .mx-md-4,body:lang(az) .ml-md-4,body:lang(az) .mx-md-4,body:lang(dv) .ml-md-4,body:lang(dv) .mx-md-4,body:lang(he) .ml-md-4,body:lang(he) .mx-md-4,body:lang(ku) .ml-md-4,body:lang(ku) .mx-md-4,body:lang(ur) .ml-md-4,body:lang(ur) .mx-md-4{-webkit-margin-start:1.5rem!important;margin-inline-start:1.5rem!important}body:lang(fa) .m-md-5,body:lang(ar) .m-md-5,body:lang(az) .m-md-5,body:lang(dv) .m-md-5,body:lang(he) .m-md-5,body:lang(ku) .m-md-5,body:lang(ur) .m-md-5{margin:3rem!important}body:lang(fa) .mt-md-5,body:lang(fa) .my-md-5,body:lang(ar) .mt-md-5,body:lang(ar) .my-md-5,body:lang(az) .mt-md-5,body:lang(az) .my-md-5,body:lang(dv) .mt-md-5,body:lang(dv) .my-md-5,body:lang(he) .mt-md-5,body:lang(he) .my-md-5,body:lang(ku) .mt-md-5,body:lang(ku) .my-md-5,body:lang(ur) .mt-md-5,body:lang(ur) .my-md-5{margin-top:3rem!important}body:lang(fa) .mr-md-5,body:lang(fa) .mx-md-5,body:lang(ar) .mr-md-5,body:lang(ar) .mx-md-5,body:lang(az) .mr-md-5,body:lang(az) .mx-md-5,body:lang(dv) .mr-md-5,body:lang(dv) .mx-md-5,body:lang(he) .mr-md-5,body:lang(he) .mx-md-5,body:lang(ku) .mr-md-5,body:lang(ku) .mx-md-5,body:lang(ur) .mr-md-5,body:lang(ur) .mx-md-5{-webkit-margin-end:3rem!important;margin-inline-end:3rem!important}body:lang(fa) .mb-md-5,body:lang(fa) .my-md-5,body:lang(ar) .mb-md-5,body:lang(ar) .my-md-5,body:lang(az) .mb-md-5,body:lang(az) .my-md-5,body:lang(dv) .mb-md-5,body:lang(dv) .my-md-5,body:lang(he) .mb-md-5,body:lang(he) .my-md-5,body:lang(ku) .mb-md-5,body:lang(ku) .my-md-5,body:lang(ur) .mb-md-5,body:lang(ur) .my-md-5{margin-bottom:3rem!important}body:lang(fa) .ml-md-5,body:lang(fa) .mx-md-5,body:lang(ar) .ml-md-5,body:lang(ar) .mx-md-5,body:lang(az) .ml-md-5,body:lang(az) .mx-md-5,body:lang(dv) .ml-md-5,body:lang(dv) .mx-md-5,body:lang(he) .ml-md-5,body:lang(he) .mx-md-5,body:lang(ku) .ml-md-5,body:lang(ku) .mx-md-5,body:lang(ur) .ml-md-5,body:lang(ur) .mx-md-5{-webkit-margin-start:3rem!important;margin-inline-start:3rem!important}body:lang(fa) .p-md-0,body:lang(ar) .p-md-0,body:lang(az) .p-md-0,body:lang(dv) .p-md-0,body:lang(he) .p-md-0,body:lang(ku) .p-md-0,body:lang(ur) .p-md-0{padding:0!important}body:lang(fa) .pt-md-0,body:lang(fa) .py-md-0,body:lang(ar) .pt-md-0,body:lang(ar) .py-md-0,body:lang(az) .pt-md-0,body:lang(az) .py-md-0,body:lang(dv) .pt-md-0,body:lang(dv) .py-md-0,body:lang(he) .pt-md-0,body:lang(he) .py-md-0,body:lang(ku) .pt-md-0,body:lang(ku) .py-md-0,body:lang(ur) .pt-md-0,body:lang(ur) .py-md-0{padding-top:0!important}body:lang(fa) .pr-md-0,body:lang(fa) .px-md-0,body:lang(ar) .pr-md-0,body:lang(ar) .px-md-0,body:lang(az) .pr-md-0,body:lang(az) .px-md-0,body:lang(dv) .pr-md-0,body:lang(dv) .px-md-0,body:lang(he) .pr-md-0,body:lang(he) .px-md-0,body:lang(ku) .pr-md-0,body:lang(ku) .px-md-0,body:lang(ur) .pr-md-0,body:lang(ur) .px-md-0{-webkit-padding-end:0!important;padding-inline-end:0!important}body:lang(fa) .pb-md-0,body:lang(fa) .py-md-0,body:lang(ar) .pb-md-0,body:lang(ar) .py-md-0,body:lang(az) .pb-md-0,body:lang(az) .py-md-0,body:lang(dv) .pb-md-0,body:lang(dv) .py-md-0,body:lang(he) .pb-md-0,body:lang(he) .py-md-0,body:lang(ku) .pb-md-0,body:lang(ku) .py-md-0,body:lang(ur) .pb-md-0,body:lang(ur) .py-md-0{padding-bottom:0!important}body:lang(fa) .pl-md-0,body:lang(fa) .px-md-0,body:lang(ar) .pl-md-0,body:lang(ar) .px-md-0,body:lang(az) .pl-md-0,body:lang(az) .px-md-0,body:lang(dv) .pl-md-0,body:lang(dv) .px-md-0,body:lang(he) .pl-md-0,body:lang(he) .px-md-0,body:lang(ku) .pl-md-0,body:lang(ku) .px-md-0,body:lang(ur) .pl-md-0,body:lang(ur) .px-md-0{-webkit-padding-start:0!important;padding-inline-start:0!important}body:lang(fa) .p-md-1,body:lang(ar) .p-md-1,body:lang(az) .p-md-1,body:lang(dv) .p-md-1,body:lang(he) .p-md-1,body:lang(ku) .p-md-1,body:lang(ur) .p-md-1{padding:.25rem!important}body:lang(fa) .pt-md-1,body:lang(fa) .py-md-1,body:lang(ar) .pt-md-1,body:lang(ar) .py-md-1,body:lang(az) .pt-md-1,body:lang(az) .py-md-1,body:lang(dv) .pt-md-1,body:lang(dv) .py-md-1,body:lang(he) .pt-md-1,body:lang(he) .py-md-1,body:lang(ku) .pt-md-1,body:lang(ku) .py-md-1,body:lang(ur) .pt-md-1,body:lang(ur) .py-md-1{padding-top:.25rem!important}body:lang(fa) .pr-md-1,body:lang(fa) .px-md-1,body:lang(ar) .pr-md-1,body:lang(ar) .px-md-1,body:lang(az) .pr-md-1,body:lang(az) .px-md-1,body:lang(dv) .pr-md-1,body:lang(dv) .px-md-1,body:lang(he) .pr-md-1,body:lang(he) .px-md-1,body:lang(ku) .pr-md-1,body:lang(ku) .px-md-1,body:lang(ur) .pr-md-1,body:lang(ur) .px-md-1{-webkit-padding-end:.25rem!important;padding-inline-end:.25rem!important}body:lang(fa) .pb-md-1,body:lang(fa) .py-md-1,body:lang(ar) .pb-md-1,body:lang(ar) .py-md-1,body:lang(az) .pb-md-1,body:lang(az) .py-md-1,body:lang(dv) .pb-md-1,body:lang(dv) .py-md-1,body:lang(he) .pb-md-1,body:lang(he) .py-md-1,body:lang(ku) .pb-md-1,body:lang(ku) .py-md-1,body:lang(ur) .pb-md-1,body:lang(ur) .py-md-1{padding-bottom:.25rem!important}body:lang(fa) .pl-md-1,body:lang(fa) .px-md-1,body:lang(ar) .pl-md-1,body:lang(ar) .px-md-1,body:lang(az) .pl-md-1,body:lang(az) .px-md-1,body:lang(dv) .pl-md-1,body:lang(dv) .px-md-1,body:lang(he) .pl-md-1,body:lang(he) .px-md-1,body:lang(ku) .pl-md-1,body:lang(ku) .px-md-1,body:lang(ur) .pl-md-1,body:lang(ur) .px-md-1{-webkit-padding-start:.25rem!important;padding-inline-start:.25rem!important}body:lang(fa) .p-md-2,body:lang(ar) .p-md-2,body:lang(az) .p-md-2,body:lang(dv) .p-md-2,body:lang(he) .p-md-2,body:lang(ku) .p-md-2,body:lang(ur) .p-md-2{padding:.5rem!important}body:lang(fa) .pt-md-2,body:lang(fa) .py-md-2,body:lang(ar) .pt-md-2,body:lang(ar) .py-md-2,body:lang(az) .pt-md-2,body:lang(az) .py-md-2,body:lang(dv) .pt-md-2,body:lang(dv) .py-md-2,body:lang(he) .pt-md-2,body:lang(he) .py-md-2,body:lang(ku) .pt-md-2,body:lang(ku) .py-md-2,body:lang(ur) .pt-md-2,body:lang(ur) .py-md-2{padding-top:.5rem!important}body:lang(fa) .pr-md-2,body:lang(fa) .px-md-2,body:lang(ar) .pr-md-2,body:lang(ar) .px-md-2,body:lang(az) .pr-md-2,body:lang(az) .px-md-2,body:lang(dv) .pr-md-2,body:lang(dv) .px-md-2,body:lang(he) .pr-md-2,body:lang(he) .px-md-2,body:lang(ku) .pr-md-2,body:lang(ku) .px-md-2,body:lang(ur) .pr-md-2,body:lang(ur) .px-md-2{-webkit-padding-end:.5rem!important;padding-inline-end:.5rem!important}body:lang(fa) .pb-md-2,body:lang(fa) .py-md-2,body:lang(ar) .pb-md-2,body:lang(ar) .py-md-2,body:lang(az) .pb-md-2,body:lang(az) .py-md-2,body:lang(dv) .pb-md-2,body:lang(dv) .py-md-2,body:lang(he) .pb-md-2,body:lang(he) .py-md-2,body:lang(ku) .pb-md-2,body:lang(ku) .py-md-2,body:lang(ur) .pb-md-2,body:lang(ur) .py-md-2{padding-bottom:.5rem!important}body:lang(fa) .pl-md-2,body:lang(fa) .px-md-2,body:lang(ar) .pl-md-2,body:lang(ar) .px-md-2,body:lang(az) .pl-md-2,body:lang(az) .px-md-2,body:lang(dv) .pl-md-2,body:lang(dv) .px-md-2,body:lang(he) .pl-md-2,body:lang(he) .px-md-2,body:lang(ku) .pl-md-2,body:lang(ku) .px-md-2,body:lang(ur) .pl-md-2,body:lang(ur) .px-md-2{-webkit-padding-start:.5rem!important;padding-inline-start:.5rem!important}body:lang(fa) .p-md-3,body:lang(ar) .p-md-3,body:lang(az) .p-md-3,body:lang(dv) .p-md-3,body:lang(he) .p-md-3,body:lang(ku) .p-md-3,body:lang(ur) .p-md-3{padding:1rem!important}body:lang(fa) .pt-md-3,body:lang(fa) .py-md-3,body:lang(ar) .pt-md-3,body:lang(ar) .py-md-3,body:lang(az) .pt-md-3,body:lang(az) .py-md-3,body:lang(dv) .pt-md-3,body:lang(dv) .py-md-3,body:lang(he) .pt-md-3,body:lang(he) .py-md-3,body:lang(ku) .pt-md-3,body:lang(ku) .py-md-3,body:lang(ur) .pt-md-3,body:lang(ur) .py-md-3{padding-top:1rem!important}body:lang(fa) .pr-md-3,body:lang(fa) .px-md-3,body:lang(ar) .pr-md-3,body:lang(ar) .px-md-3,body:lang(az) .pr-md-3,body:lang(az) .px-md-3,body:lang(dv) .pr-md-3,body:lang(dv) .px-md-3,body:lang(he) .pr-md-3,body:lang(he) .px-md-3,body:lang(ku) .pr-md-3,body:lang(ku) .px-md-3,body:lang(ur) .pr-md-3,body:lang(ur) .px-md-3{-webkit-padding-end:1rem!important;padding-inline-end:1rem!important}body:lang(fa) .pb-md-3,body:lang(fa) .py-md-3,body:lang(ar) .pb-md-3,body:lang(ar) .py-md-3,body:lang(az) .pb-md-3,body:lang(az) .py-md-3,body:lang(dv) .pb-md-3,body:lang(dv) .py-md-3,body:lang(he) .pb-md-3,body:lang(he) .py-md-3,body:lang(ku) .pb-md-3,body:lang(ku) .py-md-3,body:lang(ur) .pb-md-3,body:lang(ur) .py-md-3{padding-bottom:1rem!important}body:lang(fa) .pl-md-3,body:lang(fa) .px-md-3,body:lang(ar) .pl-md-3,body:lang(ar) .px-md-3,body:lang(az) .pl-md-3,body:lang(az) .px-md-3,body:lang(dv) .pl-md-3,body:lang(dv) .px-md-3,body:lang(he) .pl-md-3,body:lang(he) .px-md-3,body:lang(ku) .pl-md-3,body:lang(ku) .px-md-3,body:lang(ur) .pl-md-3,body:lang(ur) .px-md-3{-webkit-padding-start:1rem!important;padding-inline-start:1rem!important}body:lang(fa) .p-md-4,body:lang(ar) .p-md-4,body:lang(az) .p-md-4,body:lang(dv) .p-md-4,body:lang(he) .p-md-4,body:lang(ku) .p-md-4,body:lang(ur) .p-md-4{padding:1.5rem!important}body:lang(fa) .pt-md-4,body:lang(fa) .py-md-4,body:lang(ar) .pt-md-4,body:lang(ar) .py-md-4,body:lang(az) .pt-md-4,body:lang(az) .py-md-4,body:lang(dv) .pt-md-4,body:lang(dv) .py-md-4,body:lang(he) .pt-md-4,body:lang(he) .py-md-4,body:lang(ku) .pt-md-4,body:lang(ku) .py-md-4,body:lang(ur) .pt-md-4,body:lang(ur) .py-md-4{padding-top:1.5rem!important}body:lang(fa) .pr-md-4,body:lang(fa) .px-md-4,body:lang(ar) .pr-md-4,body:lang(ar) .px-md-4,body:lang(az) .pr-md-4,body:lang(az) .px-md-4,body:lang(dv) .pr-md-4,body:lang(dv) .px-md-4,body:lang(he) .pr-md-4,body:lang(he) .px-md-4,body:lang(ku) .pr-md-4,body:lang(ku) .px-md-4,body:lang(ur) .pr-md-4,body:lang(ur) .px-md-4{-webkit-padding-end:1.5rem!important;padding-inline-end:1.5rem!important}body:lang(fa) .pb-md-4,body:lang(fa) .py-md-4,body:lang(ar) .pb-md-4,body:lang(ar) .py-md-4,body:lang(az) .pb-md-4,body:lang(az) .py-md-4,body:lang(dv) .pb-md-4,body:lang(dv) .py-md-4,body:lang(he) .pb-md-4,body:lang(he) .py-md-4,body:lang(ku) .pb-md-4,body:lang(ku) .py-md-4,body:lang(ur) .pb-md-4,body:lang(ur) .py-md-4{padding-bottom:1.5rem!important}body:lang(fa) .pl-md-4,body:lang(fa) .px-md-4,body:lang(ar) .pl-md-4,body:lang(ar) .px-md-4,body:lang(az) .pl-md-4,body:lang(az) .px-md-4,body:lang(dv) .pl-md-4,body:lang(dv) .px-md-4,body:lang(he) .pl-md-4,body:lang(he) .px-md-4,body:lang(ku) .pl-md-4,body:lang(ku) .px-md-4,body:lang(ur) .pl-md-4,body:lang(ur) .px-md-4{-webkit-padding-start:1.5rem!important;padding-inline-start:1.5rem!important}body:lang(fa) .p-md-5,body:lang(ar) .p-md-5,body:lang(az) .p-md-5,body:lang(dv) .p-md-5,body:lang(he) .p-md-5,body:lang(ku) .p-md-5,body:lang(ur) .p-md-5{padding:3rem!important}body:lang(fa) .pt-md-5,body:lang(fa) .py-md-5,body:lang(ar) .pt-md-5,body:lang(ar) .py-md-5,body:lang(az) .pt-md-5,body:lang(az) .py-md-5,body:lang(dv) .pt-md-5,body:lang(dv) .py-md-5,body:lang(he) .pt-md-5,body:lang(he) .py-md-5,body:lang(ku) .pt-md-5,body:lang(ku) .py-md-5,body:lang(ur) .pt-md-5,body:lang(ur) .py-md-5{padding-top:3rem!important}body:lang(fa) .pr-md-5,body:lang(fa) .px-md-5,body:lang(ar) .pr-md-5,body:lang(ar) .px-md-5,body:lang(az) .pr-md-5,body:lang(az) .px-md-5,body:lang(dv) .pr-md-5,body:lang(dv) .px-md-5,body:lang(he) .pr-md-5,body:lang(he) .px-md-5,body:lang(ku) .pr-md-5,body:lang(ku) .px-md-5,body:lang(ur) .pr-md-5,body:lang(ur) .px-md-5{-webkit-padding-end:3rem!important;padding-inline-end:3rem!important}body:lang(fa) .pb-md-5,body:lang(fa) .py-md-5,body:lang(ar) .pb-md-5,body:lang(ar) .py-md-5,body:lang(az) .pb-md-5,body:lang(az) .py-md-5,body:lang(dv) .pb-md-5,body:lang(dv) .py-md-5,body:lang(he) .pb-md-5,body:lang(he) .py-md-5,body:lang(ku) .pb-md-5,body:lang(ku) .py-md-5,body:lang(ur) .pb-md-5,body:lang(ur) .py-md-5{padding-bottom:3rem!important}body:lang(fa) .pl-md-5,body:lang(fa) .px-md-5,body:lang(ar) .pl-md-5,body:lang(ar) .px-md-5,body:lang(az) .pl-md-5,body:lang(az) .px-md-5,body:lang(dv) .pl-md-5,body:lang(dv) .px-md-5,body:lang(he) .pl-md-5,body:lang(he) .px-md-5,body:lang(ku) .pl-md-5,body:lang(ku) .px-md-5,body:lang(ur) .pl-md-5,body:lang(ur) .px-md-5{-webkit-padding-start:3rem!important;padding-inline-start:3rem!important}body:lang(fa) .m-md-n1,body:lang(ar) .m-md-n1,body:lang(az) .m-md-n1,body:lang(dv) .m-md-n1,body:lang(he) .m-md-n1,body:lang(ku) .m-md-n1,body:lang(ur) .m-md-n1{margin:-.25rem!important}body:lang(fa) .mt-md-n1,body:lang(fa) .my-md-n1,body:lang(ar) .mt-md-n1,body:lang(ar) .my-md-n1,body:lang(az) .mt-md-n1,body:lang(az) .my-md-n1,body:lang(dv) .mt-md-n1,body:lang(dv) .my-md-n1,body:lang(he) .mt-md-n1,body:lang(he) .my-md-n1,body:lang(ku) .mt-md-n1,body:lang(ku) .my-md-n1,body:lang(ur) .mt-md-n1,body:lang(ur) .my-md-n1{margin-top:-.25rem!important}body:lang(fa) .mr-md-n1,body:lang(fa) .mx-md-n1,body:lang(ar) .mr-md-n1,body:lang(ar) .mx-md-n1,body:lang(az) .mr-md-n1,body:lang(az) .mx-md-n1,body:lang(dv) .mr-md-n1,body:lang(dv) .mx-md-n1,body:lang(he) .mr-md-n1,body:lang(he) .mx-md-n1,body:lang(ku) .mr-md-n1,body:lang(ku) .mx-md-n1,body:lang(ur) .mr-md-n1,body:lang(ur) .mx-md-n1{margin-right:-.25rem!important}body:lang(fa) .mb-md-n1,body:lang(fa) .my-md-n1,body:lang(ar) .mb-md-n1,body:lang(ar) .my-md-n1,body:lang(az) .mb-md-n1,body:lang(az) .my-md-n1,body:lang(dv) .mb-md-n1,body:lang(dv) .my-md-n1,body:lang(he) .mb-md-n1,body:lang(he) .my-md-n1,body:lang(ku) .mb-md-n1,body:lang(ku) .my-md-n1,body:lang(ur) .mb-md-n1,body:lang(ur) .my-md-n1{margin-bottom:-.25rem!important}body:lang(fa) .ml-md-n1,body:lang(fa) .mx-md-n1,body:lang(ar) .ml-md-n1,body:lang(ar) .mx-md-n1,body:lang(az) .ml-md-n1,body:lang(az) .mx-md-n1,body:lang(dv) .ml-md-n1,body:lang(dv) .mx-md-n1,body:lang(he) .ml-md-n1,body:lang(he) .mx-md-n1,body:lang(ku) .ml-md-n1,body:lang(ku) .mx-md-n1,body:lang(ur) .ml-md-n1,body:lang(ur) .mx-md-n1{margin-left:-.25rem!important}body:lang(fa) .m-md-n2,body:lang(ar) .m-md-n2,body:lang(az) .m-md-n2,body:lang(dv) .m-md-n2,body:lang(he) .m-md-n2,body:lang(ku) .m-md-n2,body:lang(ur) .m-md-n2{margin:-.5rem!important}body:lang(fa) .mt-md-n2,body:lang(fa) .my-md-n2,body:lang(ar) .mt-md-n2,body:lang(ar) .my-md-n2,body:lang(az) .mt-md-n2,body:lang(az) .my-md-n2,body:lang(dv) .mt-md-n2,body:lang(dv) .my-md-n2,body:lang(he) .mt-md-n2,body:lang(he) .my-md-n2,body:lang(ku) .mt-md-n2,body:lang(ku) .my-md-n2,body:lang(ur) .mt-md-n2,body:lang(ur) .my-md-n2{margin-top:-.5rem!important}body:lang(fa) .mr-md-n2,body:lang(fa) .mx-md-n2,body:lang(ar) .mr-md-n2,body:lang(ar) .mx-md-n2,body:lang(az) .mr-md-n2,body:lang(az) .mx-md-n2,body:lang(dv) .mr-md-n2,body:lang(dv) .mx-md-n2,body:lang(he) .mr-md-n2,body:lang(he) .mx-md-n2,body:lang(ku) .mr-md-n2,body:lang(ku) .mx-md-n2,body:lang(ur) .mr-md-n2,body:lang(ur) .mx-md-n2{margin-right:-.5rem!important}body:lang(fa) .mb-md-n2,body:lang(fa) .my-md-n2,body:lang(ar) .mb-md-n2,body:lang(ar) .my-md-n2,body:lang(az) .mb-md-n2,body:lang(az) .my-md-n2,body:lang(dv) .mb-md-n2,body:lang(dv) .my-md-n2,body:lang(he) .mb-md-n2,body:lang(he) .my-md-n2,body:lang(ku) .mb-md-n2,body:lang(ku) .my-md-n2,body:lang(ur) .mb-md-n2,body:lang(ur) .my-md-n2{margin-bottom:-.5rem!important}body:lang(fa) .ml-md-n2,body:lang(fa) .mx-md-n2,body:lang(ar) .ml-md-n2,body:lang(ar) .mx-md-n2,body:lang(az) .ml-md-n2,body:lang(az) .mx-md-n2,body:lang(dv) .ml-md-n2,body:lang(dv) .mx-md-n2,body:lang(he) .ml-md-n2,body:lang(he) .mx-md-n2,body:lang(ku) .ml-md-n2,body:lang(ku) .mx-md-n2,body:lang(ur) .ml-md-n2,body:lang(ur) .mx-md-n2{margin-left:-.5rem!important}body:lang(fa) .m-md-n3,body:lang(ar) .m-md-n3,body:lang(az) .m-md-n3,body:lang(dv) .m-md-n3,body:lang(he) .m-md-n3,body:lang(ku) .m-md-n3,body:lang(ur) .m-md-n3{margin:-1rem!important}body:lang(fa) .mt-md-n3,body:lang(fa) .my-md-n3,body:lang(ar) .mt-md-n3,body:lang(ar) .my-md-n3,body:lang(az) .mt-md-n3,body:lang(az) .my-md-n3,body:lang(dv) .mt-md-n3,body:lang(dv) .my-md-n3,body:lang(he) .mt-md-n3,body:lang(he) .my-md-n3,body:lang(ku) .mt-md-n3,body:lang(ku) .my-md-n3,body:lang(ur) .mt-md-n3,body:lang(ur) .my-md-n3{margin-top:-1rem!important}body:lang(fa) .mr-md-n3,body:lang(fa) .mx-md-n3,body:lang(ar) .mr-md-n3,body:lang(ar) .mx-md-n3,body:lang(az) .mr-md-n3,body:lang(az) .mx-md-n3,body:lang(dv) .mr-md-n3,body:lang(dv) .mx-md-n3,body:lang(he) .mr-md-n3,body:lang(he) .mx-md-n3,body:lang(ku) .mr-md-n3,body:lang(ku) .mx-md-n3,body:lang(ur) .mr-md-n3,body:lang(ur) .mx-md-n3{margin-right:-1rem!important}body:lang(fa) .mb-md-n3,body:lang(fa) .my-md-n3,body:lang(ar) .mb-md-n3,body:lang(ar) .my-md-n3,body:lang(az) .mb-md-n3,body:lang(az) .my-md-n3,body:lang(dv) .mb-md-n3,body:lang(dv) .my-md-n3,body:lang(he) .mb-md-n3,body:lang(he) .my-md-n3,body:lang(ku) .mb-md-n3,body:lang(ku) .my-md-n3,body:lang(ur) .mb-md-n3,body:lang(ur) .my-md-n3{margin-bottom:-1rem!important}body:lang(fa) .ml-md-n3,body:lang(fa) .mx-md-n3,body:lang(ar) .ml-md-n3,body:lang(ar) .mx-md-n3,body:lang(az) .ml-md-n3,body:lang(az) .mx-md-n3,body:lang(dv) .ml-md-n3,body:lang(dv) .mx-md-n3,body:lang(he) .ml-md-n3,body:lang(he) .mx-md-n3,body:lang(ku) .ml-md-n3,body:lang(ku) .mx-md-n3,body:lang(ur) .ml-md-n3,body:lang(ur) .mx-md-n3{margin-left:-1rem!important}body:lang(fa) .m-md-n4,body:lang(ar) .m-md-n4,body:lang(az) .m-md-n4,body:lang(dv) .m-md-n4,body:lang(he) .m-md-n4,body:lang(ku) .m-md-n4,body:lang(ur) .m-md-n4{margin:-1.5rem!important}body:lang(fa) .mt-md-n4,body:lang(fa) .my-md-n4,body:lang(ar) .mt-md-n4,body:lang(ar) .my-md-n4,body:lang(az) .mt-md-n4,body:lang(az) .my-md-n4,body:lang(dv) .mt-md-n4,body:lang(dv) .my-md-n4,body:lang(he) .mt-md-n4,body:lang(he) .my-md-n4,body:lang(ku) .mt-md-n4,body:lang(ku) .my-md-n4,body:lang(ur) .mt-md-n4,body:lang(ur) .my-md-n4{margin-top:-1.5rem!important}body:lang(fa) .mr-md-n4,body:lang(fa) .mx-md-n4,body:lang(ar) .mr-md-n4,body:lang(ar) .mx-md-n4,body:lang(az) .mr-md-n4,body:lang(az) .mx-md-n4,body:lang(dv) .mr-md-n4,body:lang(dv) .mx-md-n4,body:lang(he) .mr-md-n4,body:lang(he) .mx-md-n4,body:lang(ku) .mr-md-n4,body:lang(ku) .mx-md-n4,body:lang(ur) .mr-md-n4,body:lang(ur) .mx-md-n4{margin-right:-1.5rem!important}body:lang(fa) .mb-md-n4,body:lang(fa) .my-md-n4,body:lang(ar) .mb-md-n4,body:lang(ar) .my-md-n4,body:lang(az) .mb-md-n4,body:lang(az) .my-md-n4,body:lang(dv) .mb-md-n4,body:lang(dv) .my-md-n4,body:lang(he) .mb-md-n4,body:lang(he) .my-md-n4,body:lang(ku) .mb-md-n4,body:lang(ku) .my-md-n4,body:lang(ur) .mb-md-n4,body:lang(ur) .my-md-n4{margin-bottom:-1.5rem!important}body:lang(fa) .ml-md-n4,body:lang(fa) .mx-md-n4,body:lang(ar) .ml-md-n4,body:lang(ar) .mx-md-n4,body:lang(az) .ml-md-n4,body:lang(az) .mx-md-n4,body:lang(dv) .ml-md-n4,body:lang(dv) .mx-md-n4,body:lang(he) .ml-md-n4,body:lang(he) .mx-md-n4,body:lang(ku) .ml-md-n4,body:lang(ku) .mx-md-n4,body:lang(ur) .ml-md-n4,body:lang(ur) .mx-md-n4{margin-left:-1.5rem!important}body:lang(fa) .m-md-n5,body:lang(ar) .m-md-n5,body:lang(az) .m-md-n5,body:lang(dv) .m-md-n5,body:lang(he) .m-md-n5,body:lang(ku) .m-md-n5,body:lang(ur) .m-md-n5{margin:-3rem!important}body:lang(fa) .mt-md-n5,body:lang(fa) .my-md-n5,body:lang(ar) .mt-md-n5,body:lang(ar) .my-md-n5,body:lang(az) .mt-md-n5,body:lang(az) .my-md-n5,body:lang(dv) .mt-md-n5,body:lang(dv) .my-md-n5,body:lang(he) .mt-md-n5,body:lang(he) .my-md-n5,body:lang(ku) .mt-md-n5,body:lang(ku) .my-md-n5,body:lang(ur) .mt-md-n5,body:lang(ur) .my-md-n5{margin-top:-3rem!important}body:lang(fa) .mr-md-n5,body:lang(fa) .mx-md-n5,body:lang(ar) .mr-md-n5,body:lang(ar) .mx-md-n5,body:lang(az) .mr-md-n5,body:lang(az) .mx-md-n5,body:lang(dv) .mr-md-n5,body:lang(dv) .mx-md-n5,body:lang(he) .mr-md-n5,body:lang(he) .mx-md-n5,body:lang(ku) .mr-md-n5,body:lang(ku) .mx-md-n5,body:lang(ur) .mr-md-n5,body:lang(ur) .mx-md-n5{margin-right:-3rem!important}body:lang(fa) .mb-md-n5,body:lang(fa) .my-md-n5,body:lang(ar) .mb-md-n5,body:lang(ar) .my-md-n5,body:lang(az) .mb-md-n5,body:lang(az) .my-md-n5,body:lang(dv) .mb-md-n5,body:lang(dv) .my-md-n5,body:lang(he) .mb-md-n5,body:lang(he) .my-md-n5,body:lang(ku) .mb-md-n5,body:lang(ku) .my-md-n5,body:lang(ur) .mb-md-n5,body:lang(ur) .my-md-n5{margin-bottom:-3rem!important}body:lang(fa) .ml-md-n5,body:lang(fa) .mx-md-n5,body:lang(ar) .ml-md-n5,body:lang(ar) .mx-md-n5,body:lang(az) .ml-md-n5,body:lang(az) .mx-md-n5,body:lang(dv) .ml-md-n5,body:lang(dv) .mx-md-n5,body:lang(he) .ml-md-n5,body:lang(he) .mx-md-n5,body:lang(ku) .ml-md-n5,body:lang(ku) .mx-md-n5,body:lang(ur) .ml-md-n5,body:lang(ur) .mx-md-n5{margin-left:-3rem!important}body:lang(fa) .m-md-auto,body:lang(ar) .m-md-auto,body:lang(az) .m-md-auto,body:lang(dv) .m-md-auto,body:lang(he) .m-md-auto,body:lang(ku) .m-md-auto,body:lang(ur) .m-md-auto{margin:auto!important}body:lang(fa) .mt-md-auto,body:lang(fa) .my-md-auto,body:lang(ar) .mt-md-auto,body:lang(ar) .my-md-auto,body:lang(az) .mt-md-auto,body:lang(az) .my-md-auto,body:lang(dv) .mt-md-auto,body:lang(dv) .my-md-auto,body:lang(he) .mt-md-auto,body:lang(he) .my-md-auto,body:lang(ku) .mt-md-auto,body:lang(ku) .my-md-auto,body:lang(ur) .mt-md-auto,body:lang(ur) .my-md-auto{margin-top:auto!important}body:lang(fa) .mr-md-auto,body:lang(fa) .mx-md-auto,body:lang(ar) .mr-md-auto,body:lang(ar) .mx-md-auto,body:lang(az) .mr-md-auto,body:lang(az) .mx-md-auto,body:lang(dv) .mr-md-auto,body:lang(dv) .mx-md-auto,body:lang(he) .mr-md-auto,body:lang(he) .mx-md-auto,body:lang(ku) .mr-md-auto,body:lang(ku) .mx-md-auto,body:lang(ur) .mr-md-auto,body:lang(ur) .mx-md-auto{margin-right:auto!important}body:lang(fa) .mb-md-auto,body:lang(fa) .my-md-auto,body:lang(ar) .mb-md-auto,body:lang(ar) .my-md-auto,body:lang(az) .mb-md-auto,body:lang(az) .my-md-auto,body:lang(dv) .mb-md-auto,body:lang(dv) .my-md-auto,body:lang(he) .mb-md-auto,body:lang(he) .my-md-auto,body:lang(ku) .mb-md-auto,body:lang(ku) .my-md-auto,body:lang(ur) .mb-md-auto,body:lang(ur) .my-md-auto{margin-bottom:auto!important}body:lang(fa) .ml-md-auto,body:lang(fa) .mx-md-auto,body:lang(ar) .ml-md-auto,body:lang(ar) .mx-md-auto,body:lang(az) .ml-md-auto,body:lang(az) .mx-md-auto,body:lang(dv) .ml-md-auto,body:lang(dv) .mx-md-auto,body:lang(he) .ml-md-auto,body:lang(he) .mx-md-auto,body:lang(ku) .ml-md-auto,body:lang(ku) .mx-md-auto,body:lang(ur) .ml-md-auto,body:lang(ur) .mx-md-auto{margin-left:auto!important}}@media(min-width:992px){body:lang(fa) .m-lg-0,body:lang(ar) .m-lg-0,body:lang(az) .m-lg-0,body:lang(dv) .m-lg-0,body:lang(he) .m-lg-0,body:lang(ku) .m-lg-0,body:lang(ur) .m-lg-0{margin:0!important}body:lang(fa) .mt-lg-0,body:lang(fa) .my-lg-0,body:lang(ar) .mt-lg-0,body:lang(ar) .my-lg-0,body:lang(az) .mt-lg-0,body:lang(az) .my-lg-0,body:lang(dv) .mt-lg-0,body:lang(dv) .my-lg-0,body:lang(he) .mt-lg-0,body:lang(he) .my-lg-0,body:lang(ku) .mt-lg-0,body:lang(ku) .my-lg-0,body:lang(ur) .mt-lg-0,body:lang(ur) .my-lg-0{margin-top:0!important}body:lang(fa) .mr-lg-0,body:lang(fa) .mx-lg-0,body:lang(ar) .mr-lg-0,body:lang(ar) .mx-lg-0,body:lang(az) .mr-lg-0,body:lang(az) .mx-lg-0,body:lang(dv) .mr-lg-0,body:lang(dv) .mx-lg-0,body:lang(he) .mr-lg-0,body:lang(he) .mx-lg-0,body:lang(ku) .mr-lg-0,body:lang(ku) .mx-lg-0,body:lang(ur) .mr-lg-0,body:lang(ur) .mx-lg-0{-webkit-margin-end:0!important;margin-inline-end:0!important}body:lang(fa) .mb-lg-0,body:lang(fa) .my-lg-0,body:lang(ar) .mb-lg-0,body:lang(ar) .my-lg-0,body:lang(az) .mb-lg-0,body:lang(az) .my-lg-0,body:lang(dv) .mb-lg-0,body:lang(dv) .my-lg-0,body:lang(he) .mb-lg-0,body:lang(he) .my-lg-0,body:lang(ku) .mb-lg-0,body:lang(ku) .my-lg-0,body:lang(ur) .mb-lg-0,body:lang(ur) .my-lg-0{margin-bottom:0!important}body:lang(fa) .ml-lg-0,body:lang(fa) .mx-lg-0,body:lang(ar) .ml-lg-0,body:lang(ar) .mx-lg-0,body:lang(az) .ml-lg-0,body:lang(az) .mx-lg-0,body:lang(dv) .ml-lg-0,body:lang(dv) .mx-lg-0,body:lang(he) .ml-lg-0,body:lang(he) .mx-lg-0,body:lang(ku) .ml-lg-0,body:lang(ku) .mx-lg-0,body:lang(ur) .ml-lg-0,body:lang(ur) .mx-lg-0{-webkit-margin-start:0!important;margin-inline-start:0!important}body:lang(fa) .m-lg-1,body:lang(ar) .m-lg-1,body:lang(az) .m-lg-1,body:lang(dv) .m-lg-1,body:lang(he) .m-lg-1,body:lang(ku) .m-lg-1,body:lang(ur) .m-lg-1{margin:.25rem!important}body:lang(fa) .mt-lg-1,body:lang(fa) .my-lg-1,body:lang(ar) .mt-lg-1,body:lang(ar) .my-lg-1,body:lang(az) .mt-lg-1,body:lang(az) .my-lg-1,body:lang(dv) .mt-lg-1,body:lang(dv) .my-lg-1,body:lang(he) .mt-lg-1,body:lang(he) .my-lg-1,body:lang(ku) .mt-lg-1,body:lang(ku) .my-lg-1,body:lang(ur) .mt-lg-1,body:lang(ur) .my-lg-1{margin-top:.25rem!important}body:lang(fa) .mr-lg-1,body:lang(fa) .mx-lg-1,body:lang(ar) .mr-lg-1,body:lang(ar) .mx-lg-1,body:lang(az) .mr-lg-1,body:lang(az) .mx-lg-1,body:lang(dv) .mr-lg-1,body:lang(dv) .mx-lg-1,body:lang(he) .mr-lg-1,body:lang(he) .mx-lg-1,body:lang(ku) .mr-lg-1,body:lang(ku) .mx-lg-1,body:lang(ur) .mr-lg-1,body:lang(ur) .mx-lg-1{-webkit-margin-end:.25rem!important;margin-inline-end:.25rem!important}body:lang(fa) .mb-lg-1,body:lang(fa) .my-lg-1,body:lang(ar) .mb-lg-1,body:lang(ar) .my-lg-1,body:lang(az) .mb-lg-1,body:lang(az) .my-lg-1,body:lang(dv) .mb-lg-1,body:lang(dv) .my-lg-1,body:lang(he) .mb-lg-1,body:lang(he) .my-lg-1,body:lang(ku) .mb-lg-1,body:lang(ku) .my-lg-1,body:lang(ur) .mb-lg-1,body:lang(ur) .my-lg-1{margin-bottom:.25rem!important}body:lang(fa) .ml-lg-1,body:lang(fa) .mx-lg-1,body:lang(ar) .ml-lg-1,body:lang(ar) .mx-lg-1,body:lang(az) .ml-lg-1,body:lang(az) .mx-lg-1,body:lang(dv) .ml-lg-1,body:lang(dv) .mx-lg-1,body:lang(he) .ml-lg-1,body:lang(he) .mx-lg-1,body:lang(ku) .ml-lg-1,body:lang(ku) .mx-lg-1,body:lang(ur) .ml-lg-1,body:lang(ur) .mx-lg-1{-webkit-margin-start:.25rem!important;margin-inline-start:.25rem!important}body:lang(fa) .m-lg-2,body:lang(ar) .m-lg-2,body:lang(az) .m-lg-2,body:lang(dv) .m-lg-2,body:lang(he) .m-lg-2,body:lang(ku) .m-lg-2,body:lang(ur) .m-lg-2{margin:.5rem!important}body:lang(fa) .mt-lg-2,body:lang(fa) .my-lg-2,body:lang(ar) .mt-lg-2,body:lang(ar) .my-lg-2,body:lang(az) .mt-lg-2,body:lang(az) .my-lg-2,body:lang(dv) .mt-lg-2,body:lang(dv) .my-lg-2,body:lang(he) .mt-lg-2,body:lang(he) .my-lg-2,body:lang(ku) .mt-lg-2,body:lang(ku) .my-lg-2,body:lang(ur) .mt-lg-2,body:lang(ur) .my-lg-2{margin-top:.5rem!important}body:lang(fa) .mr-lg-2,body:lang(fa) .mx-lg-2,body:lang(ar) .mr-lg-2,body:lang(ar) .mx-lg-2,body:lang(az) .mr-lg-2,body:lang(az) .mx-lg-2,body:lang(dv) .mr-lg-2,body:lang(dv) .mx-lg-2,body:lang(he) .mr-lg-2,body:lang(he) .mx-lg-2,body:lang(ku) .mr-lg-2,body:lang(ku) .mx-lg-2,body:lang(ur) .mr-lg-2,body:lang(ur) .mx-lg-2{-webkit-margin-end:.5rem!important;margin-inline-end:.5rem!important}body:lang(fa) .mb-lg-2,body:lang(fa) .my-lg-2,body:lang(ar) .mb-lg-2,body:lang(ar) .my-lg-2,body:lang(az) .mb-lg-2,body:lang(az) .my-lg-2,body:lang(dv) .mb-lg-2,body:lang(dv) .my-lg-2,body:lang(he) .mb-lg-2,body:lang(he) .my-lg-2,body:lang(ku) .mb-lg-2,body:lang(ku) .my-lg-2,body:lang(ur) .mb-lg-2,body:lang(ur) .my-lg-2{margin-bottom:.5rem!important}body:lang(fa) .ml-lg-2,body:lang(fa) .mx-lg-2,body:lang(ar) .ml-lg-2,body:lang(ar) .mx-lg-2,body:lang(az) .ml-lg-2,body:lang(az) .mx-lg-2,body:lang(dv) .ml-lg-2,body:lang(dv) .mx-lg-2,body:lang(he) .ml-lg-2,body:lang(he) .mx-lg-2,body:lang(ku) .ml-lg-2,body:lang(ku) .mx-lg-2,body:lang(ur) .ml-lg-2,body:lang(ur) .mx-lg-2{-webkit-margin-start:.5rem!important;margin-inline-start:.5rem!important}body:lang(fa) .m-lg-3,body:lang(ar) .m-lg-3,body:lang(az) .m-lg-3,body:lang(dv) .m-lg-3,body:lang(he) .m-lg-3,body:lang(ku) .m-lg-3,body:lang(ur) .m-lg-3{margin:1rem!important}body:lang(fa) .mt-lg-3,body:lang(fa) .my-lg-3,body:lang(ar) .mt-lg-3,body:lang(ar) .my-lg-3,body:lang(az) .mt-lg-3,body:lang(az) .my-lg-3,body:lang(dv) .mt-lg-3,body:lang(dv) .my-lg-3,body:lang(he) .mt-lg-3,body:lang(he) .my-lg-3,body:lang(ku) .mt-lg-3,body:lang(ku) .my-lg-3,body:lang(ur) .mt-lg-3,body:lang(ur) .my-lg-3{margin-top:1rem!important}body:lang(fa) .mr-lg-3,body:lang(fa) .mx-lg-3,body:lang(ar) .mr-lg-3,body:lang(ar) .mx-lg-3,body:lang(az) .mr-lg-3,body:lang(az) .mx-lg-3,body:lang(dv) .mr-lg-3,body:lang(dv) .mx-lg-3,body:lang(he) .mr-lg-3,body:lang(he) .mx-lg-3,body:lang(ku) .mr-lg-3,body:lang(ku) .mx-lg-3,body:lang(ur) .mr-lg-3,body:lang(ur) .mx-lg-3{-webkit-margin-end:1rem!important;margin-inline-end:1rem!important}body:lang(fa) .mb-lg-3,body:lang(fa) .my-lg-3,body:lang(ar) .mb-lg-3,body:lang(ar) .my-lg-3,body:lang(az) .mb-lg-3,body:lang(az) .my-lg-3,body:lang(dv) .mb-lg-3,body:lang(dv) .my-lg-3,body:lang(he) .mb-lg-3,body:lang(he) .my-lg-3,body:lang(ku) .mb-lg-3,body:lang(ku) .my-lg-3,body:lang(ur) .mb-lg-3,body:lang(ur) .my-lg-3{margin-bottom:1rem!important}body:lang(fa) .ml-lg-3,body:lang(fa) .mx-lg-3,body:lang(ar) .ml-lg-3,body:lang(ar) .mx-lg-3,body:lang(az) .ml-lg-3,body:lang(az) .mx-lg-3,body:lang(dv) .ml-lg-3,body:lang(dv) .mx-lg-3,body:lang(he) .ml-lg-3,body:lang(he) .mx-lg-3,body:lang(ku) .ml-lg-3,body:lang(ku) .mx-lg-3,body:lang(ur) .ml-lg-3,body:lang(ur) .mx-lg-3{-webkit-margin-start:1rem!important;margin-inline-start:1rem!important}body:lang(fa) .m-lg-4,body:lang(ar) .m-lg-4,body:lang(az) .m-lg-4,body:lang(dv) .m-lg-4,body:lang(he) .m-lg-4,body:lang(ku) .m-lg-4,body:lang(ur) .m-lg-4{margin:1.5rem!important}body:lang(fa) .mt-lg-4,body:lang(fa) .my-lg-4,body:lang(ar) .mt-lg-4,body:lang(ar) .my-lg-4,body:lang(az) .mt-lg-4,body:lang(az) .my-lg-4,body:lang(dv) .mt-lg-4,body:lang(dv) .my-lg-4,body:lang(he) .mt-lg-4,body:lang(he) .my-lg-4,body:lang(ku) .mt-lg-4,body:lang(ku) .my-lg-4,body:lang(ur) .mt-lg-4,body:lang(ur) .my-lg-4{margin-top:1.5rem!important}body:lang(fa) .mr-lg-4,body:lang(fa) .mx-lg-4,body:lang(ar) .mr-lg-4,body:lang(ar) .mx-lg-4,body:lang(az) .mr-lg-4,body:lang(az) .mx-lg-4,body:lang(dv) .mr-lg-4,body:lang(dv) .mx-lg-4,body:lang(he) .mr-lg-4,body:lang(he) .mx-lg-4,body:lang(ku) .mr-lg-4,body:lang(ku) .mx-lg-4,body:lang(ur) .mr-lg-4,body:lang(ur) .mx-lg-4{-webkit-margin-end:1.5rem!important;margin-inline-end:1.5rem!important}body:lang(fa) .mb-lg-4,body:lang(fa) .my-lg-4,body:lang(ar) .mb-lg-4,body:lang(ar) .my-lg-4,body:lang(az) .mb-lg-4,body:lang(az) .my-lg-4,body:lang(dv) .mb-lg-4,body:lang(dv) .my-lg-4,body:lang(he) .mb-lg-4,body:lang(he) .my-lg-4,body:lang(ku) .mb-lg-4,body:lang(ku) .my-lg-4,body:lang(ur) .mb-lg-4,body:lang(ur) .my-lg-4{margin-bottom:1.5rem!important}body:lang(fa) .ml-lg-4,body:lang(fa) .mx-lg-4,body:lang(ar) .ml-lg-4,body:lang(ar) .mx-lg-4,body:lang(az) .ml-lg-4,body:lang(az) .mx-lg-4,body:lang(dv) .ml-lg-4,body:lang(dv) .mx-lg-4,body:lang(he) .ml-lg-4,body:lang(he) .mx-lg-4,body:lang(ku) .ml-lg-4,body:lang(ku) .mx-lg-4,body:lang(ur) .ml-lg-4,body:lang(ur) .mx-lg-4{-webkit-margin-start:1.5rem!important;margin-inline-start:1.5rem!important}body:lang(fa) .m-lg-5,body:lang(ar) .m-lg-5,body:lang(az) .m-lg-5,body:lang(dv) .m-lg-5,body:lang(he) .m-lg-5,body:lang(ku) .m-lg-5,body:lang(ur) .m-lg-5{margin:3rem!important}body:lang(fa) .mt-lg-5,body:lang(fa) .my-lg-5,body:lang(ar) .mt-lg-5,body:lang(ar) .my-lg-5,body:lang(az) .mt-lg-5,body:lang(az) .my-lg-5,body:lang(dv) .mt-lg-5,body:lang(dv) .my-lg-5,body:lang(he) .mt-lg-5,body:lang(he) .my-lg-5,body:lang(ku) .mt-lg-5,body:lang(ku) .my-lg-5,body:lang(ur) .mt-lg-5,body:lang(ur) .my-lg-5{margin-top:3rem!important}body:lang(fa) .mr-lg-5,body:lang(fa) .mx-lg-5,body:lang(ar) .mr-lg-5,body:lang(ar) .mx-lg-5,body:lang(az) .mr-lg-5,body:lang(az) .mx-lg-5,body:lang(dv) .mr-lg-5,body:lang(dv) .mx-lg-5,body:lang(he) .mr-lg-5,body:lang(he) .mx-lg-5,body:lang(ku) .mr-lg-5,body:lang(ku) .mx-lg-5,body:lang(ur) .mr-lg-5,body:lang(ur) .mx-lg-5{-webkit-margin-end:3rem!important;margin-inline-end:3rem!important}body:lang(fa) .mb-lg-5,body:lang(fa) .my-lg-5,body:lang(ar) .mb-lg-5,body:lang(ar) .my-lg-5,body:lang(az) .mb-lg-5,body:lang(az) .my-lg-5,body:lang(dv) .mb-lg-5,body:lang(dv) .my-lg-5,body:lang(he) .mb-lg-5,body:lang(he) .my-lg-5,body:lang(ku) .mb-lg-5,body:lang(ku) .my-lg-5,body:lang(ur) .mb-lg-5,body:lang(ur) .my-lg-5{margin-bottom:3rem!important}body:lang(fa) .ml-lg-5,body:lang(fa) .mx-lg-5,body:lang(ar) .ml-lg-5,body:lang(ar) .mx-lg-5,body:lang(az) .ml-lg-5,body:lang(az) .mx-lg-5,body:lang(dv) .ml-lg-5,body:lang(dv) .mx-lg-5,body:lang(he) .ml-lg-5,body:lang(he) .mx-lg-5,body:lang(ku) .ml-lg-5,body:lang(ku) .mx-lg-5,body:lang(ur) .ml-lg-5,body:lang(ur) .mx-lg-5{-webkit-margin-start:3rem!important;margin-inline-start:3rem!important}body:lang(fa) .p-lg-0,body:lang(ar) .p-lg-0,body:lang(az) .p-lg-0,body:lang(dv) .p-lg-0,body:lang(he) .p-lg-0,body:lang(ku) .p-lg-0,body:lang(ur) .p-lg-0{padding:0!important}body:lang(fa) .pt-lg-0,body:lang(fa) .py-lg-0,body:lang(ar) .pt-lg-0,body:lang(ar) .py-lg-0,body:lang(az) .pt-lg-0,body:lang(az) .py-lg-0,body:lang(dv) .pt-lg-0,body:lang(dv) .py-lg-0,body:lang(he) .pt-lg-0,body:lang(he) .py-lg-0,body:lang(ku) .pt-lg-0,body:lang(ku) .py-lg-0,body:lang(ur) .pt-lg-0,body:lang(ur) .py-lg-0{padding-top:0!important}body:lang(fa) .pr-lg-0,body:lang(fa) .px-lg-0,body:lang(ar) .pr-lg-0,body:lang(ar) .px-lg-0,body:lang(az) .pr-lg-0,body:lang(az) .px-lg-0,body:lang(dv) .pr-lg-0,body:lang(dv) .px-lg-0,body:lang(he) .pr-lg-0,body:lang(he) .px-lg-0,body:lang(ku) .pr-lg-0,body:lang(ku) .px-lg-0,body:lang(ur) .pr-lg-0,body:lang(ur) .px-lg-0{-webkit-padding-end:0!important;padding-inline-end:0!important}body:lang(fa) .pb-lg-0,body:lang(fa) .py-lg-0,body:lang(ar) .pb-lg-0,body:lang(ar) .py-lg-0,body:lang(az) .pb-lg-0,body:lang(az) .py-lg-0,body:lang(dv) .pb-lg-0,body:lang(dv) .py-lg-0,body:lang(he) .pb-lg-0,body:lang(he) .py-lg-0,body:lang(ku) .pb-lg-0,body:lang(ku) .py-lg-0,body:lang(ur) .pb-lg-0,body:lang(ur) .py-lg-0{padding-bottom:0!important}body:lang(fa) .pl-lg-0,body:lang(fa) .px-lg-0,body:lang(ar) .pl-lg-0,body:lang(ar) .px-lg-0,body:lang(az) .pl-lg-0,body:lang(az) .px-lg-0,body:lang(dv) .pl-lg-0,body:lang(dv) .px-lg-0,body:lang(he) .pl-lg-0,body:lang(he) .px-lg-0,body:lang(ku) .pl-lg-0,body:lang(ku) .px-lg-0,body:lang(ur) .pl-lg-0,body:lang(ur) .px-lg-0{-webkit-padding-start:0!important;padding-inline-start:0!important}body:lang(fa) .p-lg-1,body:lang(ar) .p-lg-1,body:lang(az) .p-lg-1,body:lang(dv) .p-lg-1,body:lang(he) .p-lg-1,body:lang(ku) .p-lg-1,body:lang(ur) .p-lg-1{padding:.25rem!important}body:lang(fa) .pt-lg-1,body:lang(fa) .py-lg-1,body:lang(ar) .pt-lg-1,body:lang(ar) .py-lg-1,body:lang(az) .pt-lg-1,body:lang(az) .py-lg-1,body:lang(dv) .pt-lg-1,body:lang(dv) .py-lg-1,body:lang(he) .pt-lg-1,body:lang(he) .py-lg-1,body:lang(ku) .pt-lg-1,body:lang(ku) .py-lg-1,body:lang(ur) .pt-lg-1,body:lang(ur) .py-lg-1{padding-top:.25rem!important}body:lang(fa) .pr-lg-1,body:lang(fa) .px-lg-1,body:lang(ar) .pr-lg-1,body:lang(ar) .px-lg-1,body:lang(az) .pr-lg-1,body:lang(az) .px-lg-1,body:lang(dv) .pr-lg-1,body:lang(dv) .px-lg-1,body:lang(he) .pr-lg-1,body:lang(he) .px-lg-1,body:lang(ku) .pr-lg-1,body:lang(ku) .px-lg-1,body:lang(ur) .pr-lg-1,body:lang(ur) .px-lg-1{-webkit-padding-end:.25rem!important;padding-inline-end:.25rem!important}body:lang(fa) .pb-lg-1,body:lang(fa) .py-lg-1,body:lang(ar) .pb-lg-1,body:lang(ar) .py-lg-1,body:lang(az) .pb-lg-1,body:lang(az) .py-lg-1,body:lang(dv) .pb-lg-1,body:lang(dv) .py-lg-1,body:lang(he) .pb-lg-1,body:lang(he) .py-lg-1,body:lang(ku) .pb-lg-1,body:lang(ku) .py-lg-1,body:lang(ur) .pb-lg-1,body:lang(ur) .py-lg-1{padding-bottom:.25rem!important}body:lang(fa) .pl-lg-1,body:lang(fa) .px-lg-1,body:lang(ar) .pl-lg-1,body:lang(ar) .px-lg-1,body:lang(az) .pl-lg-1,body:lang(az) .px-lg-1,body:lang(dv) .pl-lg-1,body:lang(dv) .px-lg-1,body:lang(he) .pl-lg-1,body:lang(he) .px-lg-1,body:lang(ku) .pl-lg-1,body:lang(ku) .px-lg-1,body:lang(ur) .pl-lg-1,body:lang(ur) .px-lg-1{-webkit-padding-start:.25rem!important;padding-inline-start:.25rem!important}body:lang(fa) .p-lg-2,body:lang(ar) .p-lg-2,body:lang(az) .p-lg-2,body:lang(dv) .p-lg-2,body:lang(he) .p-lg-2,body:lang(ku) .p-lg-2,body:lang(ur) .p-lg-2{padding:.5rem!important}body:lang(fa) .pt-lg-2,body:lang(fa) .py-lg-2,body:lang(ar) .pt-lg-2,body:lang(ar) .py-lg-2,body:lang(az) .pt-lg-2,body:lang(az) .py-lg-2,body:lang(dv) .pt-lg-2,body:lang(dv) .py-lg-2,body:lang(he) .pt-lg-2,body:lang(he) .py-lg-2,body:lang(ku) .pt-lg-2,body:lang(ku) .py-lg-2,body:lang(ur) .pt-lg-2,body:lang(ur) .py-lg-2{padding-top:.5rem!important}body:lang(fa) .pr-lg-2,body:lang(fa) .px-lg-2,body:lang(ar) .pr-lg-2,body:lang(ar) .px-lg-2,body:lang(az) .pr-lg-2,body:lang(az) .px-lg-2,body:lang(dv) .pr-lg-2,body:lang(dv) .px-lg-2,body:lang(he) .pr-lg-2,body:lang(he) .px-lg-2,body:lang(ku) .pr-lg-2,body:lang(ku) .px-lg-2,body:lang(ur) .pr-lg-2,body:lang(ur) .px-lg-2{-webkit-padding-end:.5rem!important;padding-inline-end:.5rem!important}body:lang(fa) .pb-lg-2,body:lang(fa) .py-lg-2,body:lang(ar) .pb-lg-2,body:lang(ar) .py-lg-2,body:lang(az) .pb-lg-2,body:lang(az) .py-lg-2,body:lang(dv) .pb-lg-2,body:lang(dv) .py-lg-2,body:lang(he) .pb-lg-2,body:lang(he) .py-lg-2,body:lang(ku) .pb-lg-2,body:lang(ku) .py-lg-2,body:lang(ur) .pb-lg-2,body:lang(ur) .py-lg-2{padding-bottom:.5rem!important}body:lang(fa) .pl-lg-2,body:lang(fa) .px-lg-2,body:lang(ar) .pl-lg-2,body:lang(ar) .px-lg-2,body:lang(az) .pl-lg-2,body:lang(az) .px-lg-2,body:lang(dv) .pl-lg-2,body:lang(dv) .px-lg-2,body:lang(he) .pl-lg-2,body:lang(he) .px-lg-2,body:lang(ku) .pl-lg-2,body:lang(ku) .px-lg-2,body:lang(ur) .pl-lg-2,body:lang(ur) .px-lg-2{-webkit-padding-start:.5rem!important;padding-inline-start:.5rem!important}body:lang(fa) .p-lg-3,body:lang(ar) .p-lg-3,body:lang(az) .p-lg-3,body:lang(dv) .p-lg-3,body:lang(he) .p-lg-3,body:lang(ku) .p-lg-3,body:lang(ur) .p-lg-3{padding:1rem!important}body:lang(fa) .pt-lg-3,body:lang(fa) .py-lg-3,body:lang(ar) .pt-lg-3,body:lang(ar) .py-lg-3,body:lang(az) .pt-lg-3,body:lang(az) .py-lg-3,body:lang(dv) .pt-lg-3,body:lang(dv) .py-lg-3,body:lang(he) .pt-lg-3,body:lang(he) .py-lg-3,body:lang(ku) .pt-lg-3,body:lang(ku) .py-lg-3,body:lang(ur) .pt-lg-3,body:lang(ur) .py-lg-3{padding-top:1rem!important}body:lang(fa) .pr-lg-3,body:lang(fa) .px-lg-3,body:lang(ar) .pr-lg-3,body:lang(ar) .px-lg-3,body:lang(az) .pr-lg-3,body:lang(az) .px-lg-3,body:lang(dv) .pr-lg-3,body:lang(dv) .px-lg-3,body:lang(he) .pr-lg-3,body:lang(he) .px-lg-3,body:lang(ku) .pr-lg-3,body:lang(ku) .px-lg-3,body:lang(ur) .pr-lg-3,body:lang(ur) .px-lg-3{-webkit-padding-end:1rem!important;padding-inline-end:1rem!important}body:lang(fa) .pb-lg-3,body:lang(fa) .py-lg-3,body:lang(ar) .pb-lg-3,body:lang(ar) .py-lg-3,body:lang(az) .pb-lg-3,body:lang(az) .py-lg-3,body:lang(dv) .pb-lg-3,body:lang(dv) .py-lg-3,body:lang(he) .pb-lg-3,body:lang(he) .py-lg-3,body:lang(ku) .pb-lg-3,body:lang(ku) .py-lg-3,body:lang(ur) .pb-lg-3,body:lang(ur) .py-lg-3{padding-bottom:1rem!important}body:lang(fa) .pl-lg-3,body:lang(fa) .px-lg-3,body:lang(ar) .pl-lg-3,body:lang(ar) .px-lg-3,body:lang(az) .pl-lg-3,body:lang(az) .px-lg-3,body:lang(dv) .pl-lg-3,body:lang(dv) .px-lg-3,body:lang(he) .pl-lg-3,body:lang(he) .px-lg-3,body:lang(ku) .pl-lg-3,body:lang(ku) .px-lg-3,body:lang(ur) .pl-lg-3,body:lang(ur) .px-lg-3{-webkit-padding-start:1rem!important;padding-inline-start:1rem!important}body:lang(fa) .p-lg-4,body:lang(ar) .p-lg-4,body:lang(az) .p-lg-4,body:lang(dv) .p-lg-4,body:lang(he) .p-lg-4,body:lang(ku) .p-lg-4,body:lang(ur) .p-lg-4{padding:1.5rem!important}body:lang(fa) .pt-lg-4,body:lang(fa) .py-lg-4,body:lang(ar) .pt-lg-4,body:lang(ar) .py-lg-4,body:lang(az) .pt-lg-4,body:lang(az) .py-lg-4,body:lang(dv) .pt-lg-4,body:lang(dv) .py-lg-4,body:lang(he) .pt-lg-4,body:lang(he) .py-lg-4,body:lang(ku) .pt-lg-4,body:lang(ku) .py-lg-4,body:lang(ur) .pt-lg-4,body:lang(ur) .py-lg-4{padding-top:1.5rem!important}body:lang(fa) .pr-lg-4,body:lang(fa) .px-lg-4,body:lang(ar) .pr-lg-4,body:lang(ar) .px-lg-4,body:lang(az) .pr-lg-4,body:lang(az) .px-lg-4,body:lang(dv) .pr-lg-4,body:lang(dv) .px-lg-4,body:lang(he) .pr-lg-4,body:lang(he) .px-lg-4,body:lang(ku) .pr-lg-4,body:lang(ku) .px-lg-4,body:lang(ur) .pr-lg-4,body:lang(ur) .px-lg-4{-webkit-padding-end:1.5rem!important;padding-inline-end:1.5rem!important}body:lang(fa) .pb-lg-4,body:lang(fa) .py-lg-4,body:lang(ar) .pb-lg-4,body:lang(ar) .py-lg-4,body:lang(az) .pb-lg-4,body:lang(az) .py-lg-4,body:lang(dv) .pb-lg-4,body:lang(dv) .py-lg-4,body:lang(he) .pb-lg-4,body:lang(he) .py-lg-4,body:lang(ku) .pb-lg-4,body:lang(ku) .py-lg-4,body:lang(ur) .pb-lg-4,body:lang(ur) .py-lg-4{padding-bottom:1.5rem!important}body:lang(fa) .pl-lg-4,body:lang(fa) .px-lg-4,body:lang(ar) .pl-lg-4,body:lang(ar) .px-lg-4,body:lang(az) .pl-lg-4,body:lang(az) .px-lg-4,body:lang(dv) .pl-lg-4,body:lang(dv) .px-lg-4,body:lang(he) .pl-lg-4,body:lang(he) .px-lg-4,body:lang(ku) .pl-lg-4,body:lang(ku) .px-lg-4,body:lang(ur) .pl-lg-4,body:lang(ur) .px-lg-4{-webkit-padding-start:1.5rem!important;padding-inline-start:1.5rem!important}body:lang(fa) .p-lg-5,body:lang(ar) .p-lg-5,body:lang(az) .p-lg-5,body:lang(dv) .p-lg-5,body:lang(he) .p-lg-5,body:lang(ku) .p-lg-5,body:lang(ur) .p-lg-5{padding:3rem!important}body:lang(fa) .pt-lg-5,body:lang(fa) .py-lg-5,body:lang(ar) .pt-lg-5,body:lang(ar) .py-lg-5,body:lang(az) .pt-lg-5,body:lang(az) .py-lg-5,body:lang(dv) .pt-lg-5,body:lang(dv) .py-lg-5,body:lang(he) .pt-lg-5,body:lang(he) .py-lg-5,body:lang(ku) .pt-lg-5,body:lang(ku) .py-lg-5,body:lang(ur) .pt-lg-5,body:lang(ur) .py-lg-5{padding-top:3rem!important}body:lang(fa) .pr-lg-5,body:lang(fa) .px-lg-5,body:lang(ar) .pr-lg-5,body:lang(ar) .px-lg-5,body:lang(az) .pr-lg-5,body:lang(az) .px-lg-5,body:lang(dv) .pr-lg-5,body:lang(dv) .px-lg-5,body:lang(he) .pr-lg-5,body:lang(he) .px-lg-5,body:lang(ku) .pr-lg-5,body:lang(ku) .px-lg-5,body:lang(ur) .pr-lg-5,body:lang(ur) .px-lg-5{-webkit-padding-end:3rem!important;padding-inline-end:3rem!important}body:lang(fa) .pb-lg-5,body:lang(fa) .py-lg-5,body:lang(ar) .pb-lg-5,body:lang(ar) .py-lg-5,body:lang(az) .pb-lg-5,body:lang(az) .py-lg-5,body:lang(dv) .pb-lg-5,body:lang(dv) .py-lg-5,body:lang(he) .pb-lg-5,body:lang(he) .py-lg-5,body:lang(ku) .pb-lg-5,body:lang(ku) .py-lg-5,body:lang(ur) .pb-lg-5,body:lang(ur) .py-lg-5{padding-bottom:3rem!important}body:lang(fa) .pl-lg-5,body:lang(fa) .px-lg-5,body:lang(ar) .pl-lg-5,body:lang(ar) .px-lg-5,body:lang(az) .pl-lg-5,body:lang(az) .px-lg-5,body:lang(dv) .pl-lg-5,body:lang(dv) .px-lg-5,body:lang(he) .pl-lg-5,body:lang(he) .px-lg-5,body:lang(ku) .pl-lg-5,body:lang(ku) .px-lg-5,body:lang(ur) .pl-lg-5,body:lang(ur) .px-lg-5{-webkit-padding-start:3rem!important;padding-inline-start:3rem!important}body:lang(fa) .m-lg-n1,body:lang(ar) .m-lg-n1,body:lang(az) .m-lg-n1,body:lang(dv) .m-lg-n1,body:lang(he) .m-lg-n1,body:lang(ku) .m-lg-n1,body:lang(ur) .m-lg-n1{margin:-.25rem!important}body:lang(fa) .mt-lg-n1,body:lang(fa) .my-lg-n1,body:lang(ar) .mt-lg-n1,body:lang(ar) .my-lg-n1,body:lang(az) .mt-lg-n1,body:lang(az) .my-lg-n1,body:lang(dv) .mt-lg-n1,body:lang(dv) .my-lg-n1,body:lang(he) .mt-lg-n1,body:lang(he) .my-lg-n1,body:lang(ku) .mt-lg-n1,body:lang(ku) .my-lg-n1,body:lang(ur) .mt-lg-n1,body:lang(ur) .my-lg-n1{margin-top:-.25rem!important}body:lang(fa) .mr-lg-n1,body:lang(fa) .mx-lg-n1,body:lang(ar) .mr-lg-n1,body:lang(ar) .mx-lg-n1,body:lang(az) .mr-lg-n1,body:lang(az) .mx-lg-n1,body:lang(dv) .mr-lg-n1,body:lang(dv) .mx-lg-n1,body:lang(he) .mr-lg-n1,body:lang(he) .mx-lg-n1,body:lang(ku) .mr-lg-n1,body:lang(ku) .mx-lg-n1,body:lang(ur) .mr-lg-n1,body:lang(ur) .mx-lg-n1{margin-right:-.25rem!important}body:lang(fa) .mb-lg-n1,body:lang(fa) .my-lg-n1,body:lang(ar) .mb-lg-n1,body:lang(ar) .my-lg-n1,body:lang(az) .mb-lg-n1,body:lang(az) .my-lg-n1,body:lang(dv) .mb-lg-n1,body:lang(dv) .my-lg-n1,body:lang(he) .mb-lg-n1,body:lang(he) .my-lg-n1,body:lang(ku) .mb-lg-n1,body:lang(ku) .my-lg-n1,body:lang(ur) .mb-lg-n1,body:lang(ur) .my-lg-n1{margin-bottom:-.25rem!important}body:lang(fa) .ml-lg-n1,body:lang(fa) .mx-lg-n1,body:lang(ar) .ml-lg-n1,body:lang(ar) .mx-lg-n1,body:lang(az) .ml-lg-n1,body:lang(az) .mx-lg-n1,body:lang(dv) .ml-lg-n1,body:lang(dv) .mx-lg-n1,body:lang(he) .ml-lg-n1,body:lang(he) .mx-lg-n1,body:lang(ku) .ml-lg-n1,body:lang(ku) .mx-lg-n1,body:lang(ur) .ml-lg-n1,body:lang(ur) .mx-lg-n1{margin-left:-.25rem!important}body:lang(fa) .m-lg-n2,body:lang(ar) .m-lg-n2,body:lang(az) .m-lg-n2,body:lang(dv) .m-lg-n2,body:lang(he) .m-lg-n2,body:lang(ku) .m-lg-n2,body:lang(ur) .m-lg-n2{margin:-.5rem!important}body:lang(fa) .mt-lg-n2,body:lang(fa) .my-lg-n2,body:lang(ar) .mt-lg-n2,body:lang(ar) .my-lg-n2,body:lang(az) .mt-lg-n2,body:lang(az) .my-lg-n2,body:lang(dv) .mt-lg-n2,body:lang(dv) .my-lg-n2,body:lang(he) .mt-lg-n2,body:lang(he) .my-lg-n2,body:lang(ku) .mt-lg-n2,body:lang(ku) .my-lg-n2,body:lang(ur) .mt-lg-n2,body:lang(ur) .my-lg-n2{margin-top:-.5rem!important}body:lang(fa) .mr-lg-n2,body:lang(fa) .mx-lg-n2,body:lang(ar) .mr-lg-n2,body:lang(ar) .mx-lg-n2,body:lang(az) .mr-lg-n2,body:lang(az) .mx-lg-n2,body:lang(dv) .mr-lg-n2,body:lang(dv) .mx-lg-n2,body:lang(he) .mr-lg-n2,body:lang(he) .mx-lg-n2,body:lang(ku) .mr-lg-n2,body:lang(ku) .mx-lg-n2,body:lang(ur) .mr-lg-n2,body:lang(ur) .mx-lg-n2{margin-right:-.5rem!important}body:lang(fa) .mb-lg-n2,body:lang(fa) .my-lg-n2,body:lang(ar) .mb-lg-n2,body:lang(ar) .my-lg-n2,body:lang(az) .mb-lg-n2,body:lang(az) .my-lg-n2,body:lang(dv) .mb-lg-n2,body:lang(dv) .my-lg-n2,body:lang(he) .mb-lg-n2,body:lang(he) .my-lg-n2,body:lang(ku) .mb-lg-n2,body:lang(ku) .my-lg-n2,body:lang(ur) .mb-lg-n2,body:lang(ur) .my-lg-n2{margin-bottom:-.5rem!important}body:lang(fa) .ml-lg-n2,body:lang(fa) .mx-lg-n2,body:lang(ar) .ml-lg-n2,body:lang(ar) .mx-lg-n2,body:lang(az) .ml-lg-n2,body:lang(az) .mx-lg-n2,body:lang(dv) .ml-lg-n2,body:lang(dv) .mx-lg-n2,body:lang(he) .ml-lg-n2,body:lang(he) .mx-lg-n2,body:lang(ku) .ml-lg-n2,body:lang(ku) .mx-lg-n2,body:lang(ur) .ml-lg-n2,body:lang(ur) .mx-lg-n2{margin-left:-.5rem!important}body:lang(fa) .m-lg-n3,body:lang(ar) .m-lg-n3,body:lang(az) .m-lg-n3,body:lang(dv) .m-lg-n3,body:lang(he) .m-lg-n3,body:lang(ku) .m-lg-n3,body:lang(ur) .m-lg-n3{margin:-1rem!important}body:lang(fa) .mt-lg-n3,body:lang(fa) .my-lg-n3,body:lang(ar) .mt-lg-n3,body:lang(ar) .my-lg-n3,body:lang(az) .mt-lg-n3,body:lang(az) .my-lg-n3,body:lang(dv) .mt-lg-n3,body:lang(dv) .my-lg-n3,body:lang(he) .mt-lg-n3,body:lang(he) .my-lg-n3,body:lang(ku) .mt-lg-n3,body:lang(ku) .my-lg-n3,body:lang(ur) .mt-lg-n3,body:lang(ur) .my-lg-n3{margin-top:-1rem!important}body:lang(fa) .mr-lg-n3,body:lang(fa) .mx-lg-n3,body:lang(ar) .mr-lg-n3,body:lang(ar) .mx-lg-n3,body:lang(az) .mr-lg-n3,body:lang(az) .mx-lg-n3,body:lang(dv) .mr-lg-n3,body:lang(dv) .mx-lg-n3,body:lang(he) .mr-lg-n3,body:lang(he) .mx-lg-n3,body:lang(ku) .mr-lg-n3,body:lang(ku) .mx-lg-n3,body:lang(ur) .mr-lg-n3,body:lang(ur) .mx-lg-n3{margin-right:-1rem!important}body:lang(fa) .mb-lg-n3,body:lang(fa) .my-lg-n3,body:lang(ar) .mb-lg-n3,body:lang(ar) .my-lg-n3,body:lang(az) .mb-lg-n3,body:lang(az) .my-lg-n3,body:lang(dv) .mb-lg-n3,body:lang(dv) .my-lg-n3,body:lang(he) .mb-lg-n3,body:lang(he) .my-lg-n3,body:lang(ku) .mb-lg-n3,body:lang(ku) .my-lg-n3,body:lang(ur) .mb-lg-n3,body:lang(ur) .my-lg-n3{margin-bottom:-1rem!important}body:lang(fa) .ml-lg-n3,body:lang(fa) .mx-lg-n3,body:lang(ar) .ml-lg-n3,body:lang(ar) .mx-lg-n3,body:lang(az) .ml-lg-n3,body:lang(az) .mx-lg-n3,body:lang(dv) .ml-lg-n3,body:lang(dv) .mx-lg-n3,body:lang(he) .ml-lg-n3,body:lang(he) .mx-lg-n3,body:lang(ku) .ml-lg-n3,body:lang(ku) .mx-lg-n3,body:lang(ur) .ml-lg-n3,body:lang(ur) .mx-lg-n3{margin-left:-1rem!important}body:lang(fa) .m-lg-n4,body:lang(ar) .m-lg-n4,body:lang(az) .m-lg-n4,body:lang(dv) .m-lg-n4,body:lang(he) .m-lg-n4,body:lang(ku) .m-lg-n4,body:lang(ur) .m-lg-n4{margin:-1.5rem!important}body:lang(fa) .mt-lg-n4,body:lang(fa) .my-lg-n4,body:lang(ar) .mt-lg-n4,body:lang(ar) .my-lg-n4,body:lang(az) .mt-lg-n4,body:lang(az) .my-lg-n4,body:lang(dv) .mt-lg-n4,body:lang(dv) .my-lg-n4,body:lang(he) .mt-lg-n4,body:lang(he) .my-lg-n4,body:lang(ku) .mt-lg-n4,body:lang(ku) .my-lg-n4,body:lang(ur) .mt-lg-n4,body:lang(ur) .my-lg-n4{margin-top:-1.5rem!important}body:lang(fa) .mr-lg-n4,body:lang(fa) .mx-lg-n4,body:lang(ar) .mr-lg-n4,body:lang(ar) .mx-lg-n4,body:lang(az) .mr-lg-n4,body:lang(az) .mx-lg-n4,body:lang(dv) .mr-lg-n4,body:lang(dv) .mx-lg-n4,body:lang(he) .mr-lg-n4,body:lang(he) .mx-lg-n4,body:lang(ku) .mr-lg-n4,body:lang(ku) .mx-lg-n4,body:lang(ur) .mr-lg-n4,body:lang(ur) .mx-lg-n4{margin-right:-1.5rem!important}body:lang(fa) .mb-lg-n4,body:lang(fa) .my-lg-n4,body:lang(ar) .mb-lg-n4,body:lang(ar) .my-lg-n4,body:lang(az) .mb-lg-n4,body:lang(az) .my-lg-n4,body:lang(dv) .mb-lg-n4,body:lang(dv) .my-lg-n4,body:lang(he) .mb-lg-n4,body:lang(he) .my-lg-n4,body:lang(ku) .mb-lg-n4,body:lang(ku) .my-lg-n4,body:lang(ur) .mb-lg-n4,body:lang(ur) .my-lg-n4{margin-bottom:-1.5rem!important}body:lang(fa) .ml-lg-n4,body:lang(fa) .mx-lg-n4,body:lang(ar) .ml-lg-n4,body:lang(ar) .mx-lg-n4,body:lang(az) .ml-lg-n4,body:lang(az) .mx-lg-n4,body:lang(dv) .ml-lg-n4,body:lang(dv) .mx-lg-n4,body:lang(he) .ml-lg-n4,body:lang(he) .mx-lg-n4,body:lang(ku) .ml-lg-n4,body:lang(ku) .mx-lg-n4,body:lang(ur) .ml-lg-n4,body:lang(ur) .mx-lg-n4{margin-left:-1.5rem!important}body:lang(fa) .m-lg-n5,body:lang(ar) .m-lg-n5,body:lang(az) .m-lg-n5,body:lang(dv) .m-lg-n5,body:lang(he) .m-lg-n5,body:lang(ku) .m-lg-n5,body:lang(ur) .m-lg-n5{margin:-3rem!important}body:lang(fa) .mt-lg-n5,body:lang(fa) .my-lg-n5,body:lang(ar) .mt-lg-n5,body:lang(ar) .my-lg-n5,body:lang(az) .mt-lg-n5,body:lang(az) .my-lg-n5,body:lang(dv) .mt-lg-n5,body:lang(dv) .my-lg-n5,body:lang(he) .mt-lg-n5,body:lang(he) .my-lg-n5,body:lang(ku) .mt-lg-n5,body:lang(ku) .my-lg-n5,body:lang(ur) .mt-lg-n5,body:lang(ur) .my-lg-n5{margin-top:-3rem!important}body:lang(fa) .mr-lg-n5,body:lang(fa) .mx-lg-n5,body:lang(ar) .mr-lg-n5,body:lang(ar) .mx-lg-n5,body:lang(az) .mr-lg-n5,body:lang(az) .mx-lg-n5,body:lang(dv) .mr-lg-n5,body:lang(dv) .mx-lg-n5,body:lang(he) .mr-lg-n5,body:lang(he) .mx-lg-n5,body:lang(ku) .mr-lg-n5,body:lang(ku) .mx-lg-n5,body:lang(ur) .mr-lg-n5,body:lang(ur) .mx-lg-n5{margin-right:-3rem!important}body:lang(fa) .mb-lg-n5,body:lang(fa) .my-lg-n5,body:lang(ar) .mb-lg-n5,body:lang(ar) .my-lg-n5,body:lang(az) .mb-lg-n5,body:lang(az) .my-lg-n5,body:lang(dv) .mb-lg-n5,body:lang(dv) .my-lg-n5,body:lang(he) .mb-lg-n5,body:lang(he) .my-lg-n5,body:lang(ku) .mb-lg-n5,body:lang(ku) .my-lg-n5,body:lang(ur) .mb-lg-n5,body:lang(ur) .my-lg-n5{margin-bottom:-3rem!important}body:lang(fa) .ml-lg-n5,body:lang(fa) .mx-lg-n5,body:lang(ar) .ml-lg-n5,body:lang(ar) .mx-lg-n5,body:lang(az) .ml-lg-n5,body:lang(az) .mx-lg-n5,body:lang(dv) .ml-lg-n5,body:lang(dv) .mx-lg-n5,body:lang(he) .ml-lg-n5,body:lang(he) .mx-lg-n5,body:lang(ku) .ml-lg-n5,body:lang(ku) .mx-lg-n5,body:lang(ur) .ml-lg-n5,body:lang(ur) .mx-lg-n5{margin-left:-3rem!important}body:lang(fa) .m-lg-auto,body:lang(ar) .m-lg-auto,body:lang(az) .m-lg-auto,body:lang(dv) .m-lg-auto,body:lang(he) .m-lg-auto,body:lang(ku) .m-lg-auto,body:lang(ur) .m-lg-auto{margin:auto!important}body:lang(fa) .mt-lg-auto,body:lang(fa) .my-lg-auto,body:lang(ar) .mt-lg-auto,body:lang(ar) .my-lg-auto,body:lang(az) .mt-lg-auto,body:lang(az) .my-lg-auto,body:lang(dv) .mt-lg-auto,body:lang(dv) .my-lg-auto,body:lang(he) .mt-lg-auto,body:lang(he) .my-lg-auto,body:lang(ku) .mt-lg-auto,body:lang(ku) .my-lg-auto,body:lang(ur) .mt-lg-auto,body:lang(ur) .my-lg-auto{margin-top:auto!important}body:lang(fa) .mr-lg-auto,body:lang(fa) .mx-lg-auto,body:lang(ar) .mr-lg-auto,body:lang(ar) .mx-lg-auto,body:lang(az) .mr-lg-auto,body:lang(az) .mx-lg-auto,body:lang(dv) .mr-lg-auto,body:lang(dv) .mx-lg-auto,body:lang(he) .mr-lg-auto,body:lang(he) .mx-lg-auto,body:lang(ku) .mr-lg-auto,body:lang(ku) .mx-lg-auto,body:lang(ur) .mr-lg-auto,body:lang(ur) .mx-lg-auto{margin-right:auto!important}body:lang(fa) .mb-lg-auto,body:lang(fa) .my-lg-auto,body:lang(ar) .mb-lg-auto,body:lang(ar) .my-lg-auto,body:lang(az) .mb-lg-auto,body:lang(az) .my-lg-auto,body:lang(dv) .mb-lg-auto,body:lang(dv) .my-lg-auto,body:lang(he) .mb-lg-auto,body:lang(he) .my-lg-auto,body:lang(ku) .mb-lg-auto,body:lang(ku) .my-lg-auto,body:lang(ur) .mb-lg-auto,body:lang(ur) .my-lg-auto{margin-bottom:auto!important}body:lang(fa) .ml-lg-auto,body:lang(fa) .mx-lg-auto,body:lang(ar) .ml-lg-auto,body:lang(ar) .mx-lg-auto,body:lang(az) .ml-lg-auto,body:lang(az) .mx-lg-auto,body:lang(dv) .ml-lg-auto,body:lang(dv) .mx-lg-auto,body:lang(he) .ml-lg-auto,body:lang(he) .mx-lg-auto,body:lang(ku) .ml-lg-auto,body:lang(ku) .mx-lg-auto,body:lang(ur) .ml-lg-auto,body:lang(ur) .mx-lg-auto{margin-left:auto!important}}@media(min-width:1200px){body:lang(fa) .m-xl-0,body:lang(ar) .m-xl-0,body:lang(az) .m-xl-0,body:lang(dv) .m-xl-0,body:lang(he) .m-xl-0,body:lang(ku) .m-xl-0,body:lang(ur) .m-xl-0{margin:0!important}body:lang(fa) .mt-xl-0,body:lang(fa) .my-xl-0,body:lang(ar) .mt-xl-0,body:lang(ar) .my-xl-0,body:lang(az) .mt-xl-0,body:lang(az) .my-xl-0,body:lang(dv) .mt-xl-0,body:lang(dv) .my-xl-0,body:lang(he) .mt-xl-0,body:lang(he) .my-xl-0,body:lang(ku) .mt-xl-0,body:lang(ku) .my-xl-0,body:lang(ur) .mt-xl-0,body:lang(ur) .my-xl-0{margin-top:0!important}body:lang(fa) .mr-xl-0,body:lang(fa) .mx-xl-0,body:lang(ar) .mr-xl-0,body:lang(ar) .mx-xl-0,body:lang(az) .mr-xl-0,body:lang(az) .mx-xl-0,body:lang(dv) .mr-xl-0,body:lang(dv) .mx-xl-0,body:lang(he) .mr-xl-0,body:lang(he) .mx-xl-0,body:lang(ku) .mr-xl-0,body:lang(ku) .mx-xl-0,body:lang(ur) .mr-xl-0,body:lang(ur) .mx-xl-0{-webkit-margin-end:0!important;margin-inline-end:0!important}body:lang(fa) .mb-xl-0,body:lang(fa) .my-xl-0,body:lang(ar) .mb-xl-0,body:lang(ar) .my-xl-0,body:lang(az) .mb-xl-0,body:lang(az) .my-xl-0,body:lang(dv) .mb-xl-0,body:lang(dv) .my-xl-0,body:lang(he) .mb-xl-0,body:lang(he) .my-xl-0,body:lang(ku) .mb-xl-0,body:lang(ku) .my-xl-0,body:lang(ur) .mb-xl-0,body:lang(ur) .my-xl-0{margin-bottom:0!important}body:lang(fa) .ml-xl-0,body:lang(fa) .mx-xl-0,body:lang(ar) .ml-xl-0,body:lang(ar) .mx-xl-0,body:lang(az) .ml-xl-0,body:lang(az) .mx-xl-0,body:lang(dv) .ml-xl-0,body:lang(dv) .mx-xl-0,body:lang(he) .ml-xl-0,body:lang(he) .mx-xl-0,body:lang(ku) .ml-xl-0,body:lang(ku) .mx-xl-0,body:lang(ur) .ml-xl-0,body:lang(ur) .mx-xl-0{-webkit-margin-start:0!important;margin-inline-start:0!important}body:lang(fa) .m-xl-1,body:lang(ar) .m-xl-1,body:lang(az) .m-xl-1,body:lang(dv) .m-xl-1,body:lang(he) .m-xl-1,body:lang(ku) .m-xl-1,body:lang(ur) .m-xl-1{margin:.25rem!important}body:lang(fa) .mt-xl-1,body:lang(fa) .my-xl-1,body:lang(ar) .mt-xl-1,body:lang(ar) .my-xl-1,body:lang(az) .mt-xl-1,body:lang(az) .my-xl-1,body:lang(dv) .mt-xl-1,body:lang(dv) .my-xl-1,body:lang(he) .mt-xl-1,body:lang(he) .my-xl-1,body:lang(ku) .mt-xl-1,body:lang(ku) .my-xl-1,body:lang(ur) .mt-xl-1,body:lang(ur) .my-xl-1{margin-top:.25rem!important}body:lang(fa) .mr-xl-1,body:lang(fa) .mx-xl-1,body:lang(ar) .mr-xl-1,body:lang(ar) .mx-xl-1,body:lang(az) .mr-xl-1,body:lang(az) .mx-xl-1,body:lang(dv) .mr-xl-1,body:lang(dv) .mx-xl-1,body:lang(he) .mr-xl-1,body:lang(he) .mx-xl-1,body:lang(ku) .mr-xl-1,body:lang(ku) .mx-xl-1,body:lang(ur) .mr-xl-1,body:lang(ur) .mx-xl-1{-webkit-margin-end:.25rem!important;margin-inline-end:.25rem!important}body:lang(fa) .mb-xl-1,body:lang(fa) .my-xl-1,body:lang(ar) .mb-xl-1,body:lang(ar) .my-xl-1,body:lang(az) .mb-xl-1,body:lang(az) .my-xl-1,body:lang(dv) .mb-xl-1,body:lang(dv) .my-xl-1,body:lang(he) .mb-xl-1,body:lang(he) .my-xl-1,body:lang(ku) .mb-xl-1,body:lang(ku) .my-xl-1,body:lang(ur) .mb-xl-1,body:lang(ur) .my-xl-1{margin-bottom:.25rem!important}body:lang(fa) .ml-xl-1,body:lang(fa) .mx-xl-1,body:lang(ar) .ml-xl-1,body:lang(ar) .mx-xl-1,body:lang(az) .ml-xl-1,body:lang(az) .mx-xl-1,body:lang(dv) .ml-xl-1,body:lang(dv) .mx-xl-1,body:lang(he) .ml-xl-1,body:lang(he) .mx-xl-1,body:lang(ku) .ml-xl-1,body:lang(ku) .mx-xl-1,body:lang(ur) .ml-xl-1,body:lang(ur) .mx-xl-1{-webkit-margin-start:.25rem!important;margin-inline-start:.25rem!important}body:lang(fa) .m-xl-2,body:lang(ar) .m-xl-2,body:lang(az) .m-xl-2,body:lang(dv) .m-xl-2,body:lang(he) .m-xl-2,body:lang(ku) .m-xl-2,body:lang(ur) .m-xl-2{margin:.5rem!important}body:lang(fa) .mt-xl-2,body:lang(fa) .my-xl-2,body:lang(ar) .mt-xl-2,body:lang(ar) .my-xl-2,body:lang(az) .mt-xl-2,body:lang(az) .my-xl-2,body:lang(dv) .mt-xl-2,body:lang(dv) .my-xl-2,body:lang(he) .mt-xl-2,body:lang(he) .my-xl-2,body:lang(ku) .mt-xl-2,body:lang(ku) .my-xl-2,body:lang(ur) .mt-xl-2,body:lang(ur) .my-xl-2{margin-top:.5rem!important}body:lang(fa) .mr-xl-2,body:lang(fa) .mx-xl-2,body:lang(ar) .mr-xl-2,body:lang(ar) .mx-xl-2,body:lang(az) .mr-xl-2,body:lang(az) .mx-xl-2,body:lang(dv) .mr-xl-2,body:lang(dv) .mx-xl-2,body:lang(he) .mr-xl-2,body:lang(he) .mx-xl-2,body:lang(ku) .mr-xl-2,body:lang(ku) .mx-xl-2,body:lang(ur) .mr-xl-2,body:lang(ur) .mx-xl-2{-webkit-margin-end:.5rem!important;margin-inline-end:.5rem!important}body:lang(fa) .mb-xl-2,body:lang(fa) .my-xl-2,body:lang(ar) .mb-xl-2,body:lang(ar) .my-xl-2,body:lang(az) .mb-xl-2,body:lang(az) .my-xl-2,body:lang(dv) .mb-xl-2,body:lang(dv) .my-xl-2,body:lang(he) .mb-xl-2,body:lang(he) .my-xl-2,body:lang(ku) .mb-xl-2,body:lang(ku) .my-xl-2,body:lang(ur) .mb-xl-2,body:lang(ur) .my-xl-2{margin-bottom:.5rem!important}body:lang(fa) .ml-xl-2,body:lang(fa) .mx-xl-2,body:lang(ar) .ml-xl-2,body:lang(ar) .mx-xl-2,body:lang(az) .ml-xl-2,body:lang(az) .mx-xl-2,body:lang(dv) .ml-xl-2,body:lang(dv) .mx-xl-2,body:lang(he) .ml-xl-2,body:lang(he) .mx-xl-2,body:lang(ku) .ml-xl-2,body:lang(ku) .mx-xl-2,body:lang(ur) .ml-xl-2,body:lang(ur) .mx-xl-2{-webkit-margin-start:.5rem!important;margin-inline-start:.5rem!important}body:lang(fa) .m-xl-3,body:lang(ar) .m-xl-3,body:lang(az) .m-xl-3,body:lang(dv) .m-xl-3,body:lang(he) .m-xl-3,body:lang(ku) .m-xl-3,body:lang(ur) .m-xl-3{margin:1rem!important}body:lang(fa) .mt-xl-3,body:lang(fa) .my-xl-3,body:lang(ar) .mt-xl-3,body:lang(ar) .my-xl-3,body:lang(az) .mt-xl-3,body:lang(az) .my-xl-3,body:lang(dv) .mt-xl-3,body:lang(dv) .my-xl-3,body:lang(he) .mt-xl-3,body:lang(he) .my-xl-3,body:lang(ku) .mt-xl-3,body:lang(ku) .my-xl-3,body:lang(ur) .mt-xl-3,body:lang(ur) .my-xl-3{margin-top:1rem!important}body:lang(fa) .mr-xl-3,body:lang(fa) .mx-xl-3,body:lang(ar) .mr-xl-3,body:lang(ar) .mx-xl-3,body:lang(az) .mr-xl-3,body:lang(az) .mx-xl-3,body:lang(dv) .mr-xl-3,body:lang(dv) .mx-xl-3,body:lang(he) .mr-xl-3,body:lang(he) .mx-xl-3,body:lang(ku) .mr-xl-3,body:lang(ku) .mx-xl-3,body:lang(ur) .mr-xl-3,body:lang(ur) .mx-xl-3{-webkit-margin-end:1rem!important;margin-inline-end:1rem!important}body:lang(fa) .mb-xl-3,body:lang(fa) .my-xl-3,body:lang(ar) .mb-xl-3,body:lang(ar) .my-xl-3,body:lang(az) .mb-xl-3,body:lang(az) .my-xl-3,body:lang(dv) .mb-xl-3,body:lang(dv) .my-xl-3,body:lang(he) .mb-xl-3,body:lang(he) .my-xl-3,body:lang(ku) .mb-xl-3,body:lang(ku) .my-xl-3,body:lang(ur) .mb-xl-3,body:lang(ur) .my-xl-3{margin-bottom:1rem!important}body:lang(fa) .ml-xl-3,body:lang(fa) .mx-xl-3,body:lang(ar) .ml-xl-3,body:lang(ar) .mx-xl-3,body:lang(az) .ml-xl-3,body:lang(az) .mx-xl-3,body:lang(dv) .ml-xl-3,body:lang(dv) .mx-xl-3,body:lang(he) .ml-xl-3,body:lang(he) .mx-xl-3,body:lang(ku) .ml-xl-3,body:lang(ku) .mx-xl-3,body:lang(ur) .ml-xl-3,body:lang(ur) .mx-xl-3{-webkit-margin-start:1rem!important;margin-inline-start:1rem!important}body:lang(fa) .m-xl-4,body:lang(ar) .m-xl-4,body:lang(az) .m-xl-4,body:lang(dv) .m-xl-4,body:lang(he) .m-xl-4,body:lang(ku) .m-xl-4,body:lang(ur) .m-xl-4{margin:1.5rem!important}body:lang(fa) .mt-xl-4,body:lang(fa) .my-xl-4,body:lang(ar) .mt-xl-4,body:lang(ar) .my-xl-4,body:lang(az) .mt-xl-4,body:lang(az) .my-xl-4,body:lang(dv) .mt-xl-4,body:lang(dv) .my-xl-4,body:lang(he) .mt-xl-4,body:lang(he) .my-xl-4,body:lang(ku) .mt-xl-4,body:lang(ku) .my-xl-4,body:lang(ur) .mt-xl-4,body:lang(ur) .my-xl-4{margin-top:1.5rem!important}body:lang(fa) .mr-xl-4,body:lang(fa) .mx-xl-4,body:lang(ar) .mr-xl-4,body:lang(ar) .mx-xl-4,body:lang(az) .mr-xl-4,body:lang(az) .mx-xl-4,body:lang(dv) .mr-xl-4,body:lang(dv) .mx-xl-4,body:lang(he) .mr-xl-4,body:lang(he) .mx-xl-4,body:lang(ku) .mr-xl-4,body:lang(ku) .mx-xl-4,body:lang(ur) .mr-xl-4,body:lang(ur) .mx-xl-4{-webkit-margin-end:1.5rem!important;margin-inline-end:1.5rem!important}body:lang(fa) .mb-xl-4,body:lang(fa) .my-xl-4,body:lang(ar) .mb-xl-4,body:lang(ar) .my-xl-4,body:lang(az) .mb-xl-4,body:lang(az) .my-xl-4,body:lang(dv) .mb-xl-4,body:lang(dv) .my-xl-4,body:lang(he) .mb-xl-4,body:lang(he) .my-xl-4,body:lang(ku) .mb-xl-4,body:lang(ku) .my-xl-4,body:lang(ur) .mb-xl-4,body:lang(ur) .my-xl-4{margin-bottom:1.5rem!important}body:lang(fa) .ml-xl-4,body:lang(fa) .mx-xl-4,body:lang(ar) .ml-xl-4,body:lang(ar) .mx-xl-4,body:lang(az) .ml-xl-4,body:lang(az) .mx-xl-4,body:lang(dv) .ml-xl-4,body:lang(dv) .mx-xl-4,body:lang(he) .ml-xl-4,body:lang(he) .mx-xl-4,body:lang(ku) .ml-xl-4,body:lang(ku) .mx-xl-4,body:lang(ur) .ml-xl-4,body:lang(ur) .mx-xl-4{-webkit-margin-start:1.5rem!important;margin-inline-start:1.5rem!important}body:lang(fa) .m-xl-5,body:lang(ar) .m-xl-5,body:lang(az) .m-xl-5,body:lang(dv) .m-xl-5,body:lang(he) .m-xl-5,body:lang(ku) .m-xl-5,body:lang(ur) .m-xl-5{margin:3rem!important}body:lang(fa) .mt-xl-5,body:lang(fa) .my-xl-5,body:lang(ar) .mt-xl-5,body:lang(ar) .my-xl-5,body:lang(az) .mt-xl-5,body:lang(az) .my-xl-5,body:lang(dv) .mt-xl-5,body:lang(dv) .my-xl-5,body:lang(he) .mt-xl-5,body:lang(he) .my-xl-5,body:lang(ku) .mt-xl-5,body:lang(ku) .my-xl-5,body:lang(ur) .mt-xl-5,body:lang(ur) .my-xl-5{margin-top:3rem!important}body:lang(fa) .mr-xl-5,body:lang(fa) .mx-xl-5,body:lang(ar) .mr-xl-5,body:lang(ar) .mx-xl-5,body:lang(az) .mr-xl-5,body:lang(az) .mx-xl-5,body:lang(dv) .mr-xl-5,body:lang(dv) .mx-xl-5,body:lang(he) .mr-xl-5,body:lang(he) .mx-xl-5,body:lang(ku) .mr-xl-5,body:lang(ku) .mx-xl-5,body:lang(ur) .mr-xl-5,body:lang(ur) .mx-xl-5{-webkit-margin-end:3rem!important;margin-inline-end:3rem!important}body:lang(fa) .mb-xl-5,body:lang(fa) .my-xl-5,body:lang(ar) .mb-xl-5,body:lang(ar) .my-xl-5,body:lang(az) .mb-xl-5,body:lang(az) .my-xl-5,body:lang(dv) .mb-xl-5,body:lang(dv) .my-xl-5,body:lang(he) .mb-xl-5,body:lang(he) .my-xl-5,body:lang(ku) .mb-xl-5,body:lang(ku) .my-xl-5,body:lang(ur) .mb-xl-5,body:lang(ur) .my-xl-5{margin-bottom:3rem!important}body:lang(fa) .ml-xl-5,body:lang(fa) .mx-xl-5,body:lang(ar) .ml-xl-5,body:lang(ar) .mx-xl-5,body:lang(az) .ml-xl-5,body:lang(az) .mx-xl-5,body:lang(dv) .ml-xl-5,body:lang(dv) .mx-xl-5,body:lang(he) .ml-xl-5,body:lang(he) .mx-xl-5,body:lang(ku) .ml-xl-5,body:lang(ku) .mx-xl-5,body:lang(ur) .ml-xl-5,body:lang(ur) .mx-xl-5{-webkit-margin-start:3rem!important;margin-inline-start:3rem!important}body:lang(fa) .p-xl-0,body:lang(ar) .p-xl-0,body:lang(az) .p-xl-0,body:lang(dv) .p-xl-0,body:lang(he) .p-xl-0,body:lang(ku) .p-xl-0,body:lang(ur) .p-xl-0{padding:0!important}body:lang(fa) .pt-xl-0,body:lang(fa) .py-xl-0,body:lang(ar) .pt-xl-0,body:lang(ar) .py-xl-0,body:lang(az) .pt-xl-0,body:lang(az) .py-xl-0,body:lang(dv) .pt-xl-0,body:lang(dv) .py-xl-0,body:lang(he) .pt-xl-0,body:lang(he) .py-xl-0,body:lang(ku) .pt-xl-0,body:lang(ku) .py-xl-0,body:lang(ur) .pt-xl-0,body:lang(ur) .py-xl-0{padding-top:0!important}body:lang(fa) .pr-xl-0,body:lang(fa) .px-xl-0,body:lang(ar) .pr-xl-0,body:lang(ar) .px-xl-0,body:lang(az) .pr-xl-0,body:lang(az) .px-xl-0,body:lang(dv) .pr-xl-0,body:lang(dv) .px-xl-0,body:lang(he) .pr-xl-0,body:lang(he) .px-xl-0,body:lang(ku) .pr-xl-0,body:lang(ku) .px-xl-0,body:lang(ur) .pr-xl-0,body:lang(ur) .px-xl-0{-webkit-padding-end:0!important;padding-inline-end:0!important}body:lang(fa) .pb-xl-0,body:lang(fa) .py-xl-0,body:lang(ar) .pb-xl-0,body:lang(ar) .py-xl-0,body:lang(az) .pb-xl-0,body:lang(az) .py-xl-0,body:lang(dv) .pb-xl-0,body:lang(dv) .py-xl-0,body:lang(he) .pb-xl-0,body:lang(he) .py-xl-0,body:lang(ku) .pb-xl-0,body:lang(ku) .py-xl-0,body:lang(ur) .pb-xl-0,body:lang(ur) .py-xl-0{padding-bottom:0!important}body:lang(fa) .pl-xl-0,body:lang(fa) .px-xl-0,body:lang(ar) .pl-xl-0,body:lang(ar) .px-xl-0,body:lang(az) .pl-xl-0,body:lang(az) .px-xl-0,body:lang(dv) .pl-xl-0,body:lang(dv) .px-xl-0,body:lang(he) .pl-xl-0,body:lang(he) .px-xl-0,body:lang(ku) .pl-xl-0,body:lang(ku) .px-xl-0,body:lang(ur) .pl-xl-0,body:lang(ur) .px-xl-0{-webkit-padding-start:0!important;padding-inline-start:0!important}body:lang(fa) .p-xl-1,body:lang(ar) .p-xl-1,body:lang(az) .p-xl-1,body:lang(dv) .p-xl-1,body:lang(he) .p-xl-1,body:lang(ku) .p-xl-1,body:lang(ur) .p-xl-1{padding:.25rem!important}body:lang(fa) .pt-xl-1,body:lang(fa) .py-xl-1,body:lang(ar) .pt-xl-1,body:lang(ar) .py-xl-1,body:lang(az) .pt-xl-1,body:lang(az) .py-xl-1,body:lang(dv) .pt-xl-1,body:lang(dv) .py-xl-1,body:lang(he) .pt-xl-1,body:lang(he) .py-xl-1,body:lang(ku) .pt-xl-1,body:lang(ku) .py-xl-1,body:lang(ur) .pt-xl-1,body:lang(ur) .py-xl-1{padding-top:.25rem!important}body:lang(fa) .pr-xl-1,body:lang(fa) .px-xl-1,body:lang(ar) .pr-xl-1,body:lang(ar) .px-xl-1,body:lang(az) .pr-xl-1,body:lang(az) .px-xl-1,body:lang(dv) .pr-xl-1,body:lang(dv) .px-xl-1,body:lang(he) .pr-xl-1,body:lang(he) .px-xl-1,body:lang(ku) .pr-xl-1,body:lang(ku) .px-xl-1,body:lang(ur) .pr-xl-1,body:lang(ur) .px-xl-1{-webkit-padding-end:.25rem!important;padding-inline-end:.25rem!important}body:lang(fa) .pb-xl-1,body:lang(fa) .py-xl-1,body:lang(ar) .pb-xl-1,body:lang(ar) .py-xl-1,body:lang(az) .pb-xl-1,body:lang(az) .py-xl-1,body:lang(dv) .pb-xl-1,body:lang(dv) .py-xl-1,body:lang(he) .pb-xl-1,body:lang(he) .py-xl-1,body:lang(ku) .pb-xl-1,body:lang(ku) .py-xl-1,body:lang(ur) .pb-xl-1,body:lang(ur) .py-xl-1{padding-bottom:.25rem!important}body:lang(fa) .pl-xl-1,body:lang(fa) .px-xl-1,body:lang(ar) .pl-xl-1,body:lang(ar) .px-xl-1,body:lang(az) .pl-xl-1,body:lang(az) .px-xl-1,body:lang(dv) .pl-xl-1,body:lang(dv) .px-xl-1,body:lang(he) .pl-xl-1,body:lang(he) .px-xl-1,body:lang(ku) .pl-xl-1,body:lang(ku) .px-xl-1,body:lang(ur) .pl-xl-1,body:lang(ur) .px-xl-1{-webkit-padding-start:.25rem!important;padding-inline-start:.25rem!important}body:lang(fa) .p-xl-2,body:lang(ar) .p-xl-2,body:lang(az) .p-xl-2,body:lang(dv) .p-xl-2,body:lang(he) .p-xl-2,body:lang(ku) .p-xl-2,body:lang(ur) .p-xl-2{padding:.5rem!important}body:lang(fa) .pt-xl-2,body:lang(fa) .py-xl-2,body:lang(ar) .pt-xl-2,body:lang(ar) .py-xl-2,body:lang(az) .pt-xl-2,body:lang(az) .py-xl-2,body:lang(dv) .pt-xl-2,body:lang(dv) .py-xl-2,body:lang(he) .pt-xl-2,body:lang(he) .py-xl-2,body:lang(ku) .pt-xl-2,body:lang(ku) .py-xl-2,body:lang(ur) .pt-xl-2,body:lang(ur) .py-xl-2{padding-top:.5rem!important}body:lang(fa) .pr-xl-2,body:lang(fa) .px-xl-2,body:lang(ar) .pr-xl-2,body:lang(ar) .px-xl-2,body:lang(az) .pr-xl-2,body:lang(az) .px-xl-2,body:lang(dv) .pr-xl-2,body:lang(dv) .px-xl-2,body:lang(he) .pr-xl-2,body:lang(he) .px-xl-2,body:lang(ku) .pr-xl-2,body:lang(ku) .px-xl-2,body:lang(ur) .pr-xl-2,body:lang(ur) .px-xl-2{-webkit-padding-end:.5rem!important;padding-inline-end:.5rem!important}body:lang(fa) .pb-xl-2,body:lang(fa) .py-xl-2,body:lang(ar) .pb-xl-2,body:lang(ar) .py-xl-2,body:lang(az) .pb-xl-2,body:lang(az) .py-xl-2,body:lang(dv) .pb-xl-2,body:lang(dv) .py-xl-2,body:lang(he) .pb-xl-2,body:lang(he) .py-xl-2,body:lang(ku) .pb-xl-2,body:lang(ku) .py-xl-2,body:lang(ur) .pb-xl-2,body:lang(ur) .py-xl-2{padding-bottom:.5rem!important}body:lang(fa) .pl-xl-2,body:lang(fa) .px-xl-2,body:lang(ar) .pl-xl-2,body:lang(ar) .px-xl-2,body:lang(az) .pl-xl-2,body:lang(az) .px-xl-2,body:lang(dv) .pl-xl-2,body:lang(dv) .px-xl-2,body:lang(he) .pl-xl-2,body:lang(he) .px-xl-2,body:lang(ku) .pl-xl-2,body:lang(ku) .px-xl-2,body:lang(ur) .pl-xl-2,body:lang(ur) .px-xl-2{-webkit-padding-start:.5rem!important;padding-inline-start:.5rem!important}body:lang(fa) .p-xl-3,body:lang(ar) .p-xl-3,body:lang(az) .p-xl-3,body:lang(dv) .p-xl-3,body:lang(he) .p-xl-3,body:lang(ku) .p-xl-3,body:lang(ur) .p-xl-3{padding:1rem!important}body:lang(fa) .pt-xl-3,body:lang(fa) .py-xl-3,body:lang(ar) .pt-xl-3,body:lang(ar) .py-xl-3,body:lang(az) .pt-xl-3,body:lang(az) .py-xl-3,body:lang(dv) .pt-xl-3,body:lang(dv) .py-xl-3,body:lang(he) .pt-xl-3,body:lang(he) .py-xl-3,body:lang(ku) .pt-xl-3,body:lang(ku) .py-xl-3,body:lang(ur) .pt-xl-3,body:lang(ur) .py-xl-3{padding-top:1rem!important}body:lang(fa) .pr-xl-3,body:lang(fa) .px-xl-3,body:lang(ar) .pr-xl-3,body:lang(ar) .px-xl-3,body:lang(az) .pr-xl-3,body:lang(az) .px-xl-3,body:lang(dv) .pr-xl-3,body:lang(dv) .px-xl-3,body:lang(he) .pr-xl-3,body:lang(he) .px-xl-3,body:lang(ku) .pr-xl-3,body:lang(ku) .px-xl-3,body:lang(ur) .pr-xl-3,body:lang(ur) .px-xl-3{-webkit-padding-end:1rem!important;padding-inline-end:1rem!important}body:lang(fa) .pb-xl-3,body:lang(fa) .py-xl-3,body:lang(ar) .pb-xl-3,body:lang(ar) .py-xl-3,body:lang(az) .pb-xl-3,body:lang(az) .py-xl-3,body:lang(dv) .pb-xl-3,body:lang(dv) .py-xl-3,body:lang(he) .pb-xl-3,body:lang(he) .py-xl-3,body:lang(ku) .pb-xl-3,body:lang(ku) .py-xl-3,body:lang(ur) .pb-xl-3,body:lang(ur) .py-xl-3{padding-bottom:1rem!important}body:lang(fa) .pl-xl-3,body:lang(fa) .px-xl-3,body:lang(ar) .pl-xl-3,body:lang(ar) .px-xl-3,body:lang(az) .pl-xl-3,body:lang(az) .px-xl-3,body:lang(dv) .pl-xl-3,body:lang(dv) .px-xl-3,body:lang(he) .pl-xl-3,body:lang(he) .px-xl-3,body:lang(ku) .pl-xl-3,body:lang(ku) .px-xl-3,body:lang(ur) .pl-xl-3,body:lang(ur) .px-xl-3{-webkit-padding-start:1rem!important;padding-inline-start:1rem!important}body:lang(fa) .p-xl-4,body:lang(ar) .p-xl-4,body:lang(az) .p-xl-4,body:lang(dv) .p-xl-4,body:lang(he) .p-xl-4,body:lang(ku) .p-xl-4,body:lang(ur) .p-xl-4{padding:1.5rem!important}body:lang(fa) .pt-xl-4,body:lang(fa) .py-xl-4,body:lang(ar) .pt-xl-4,body:lang(ar) .py-xl-4,body:lang(az) .pt-xl-4,body:lang(az) .py-xl-4,body:lang(dv) .pt-xl-4,body:lang(dv) .py-xl-4,body:lang(he) .pt-xl-4,body:lang(he) .py-xl-4,body:lang(ku) .pt-xl-4,body:lang(ku) .py-xl-4,body:lang(ur) .pt-xl-4,body:lang(ur) .py-xl-4{padding-top:1.5rem!important}body:lang(fa) .pr-xl-4,body:lang(fa) .px-xl-4,body:lang(ar) .pr-xl-4,body:lang(ar) .px-xl-4,body:lang(az) .pr-xl-4,body:lang(az) .px-xl-4,body:lang(dv) .pr-xl-4,body:lang(dv) .px-xl-4,body:lang(he) .pr-xl-4,body:lang(he) .px-xl-4,body:lang(ku) .pr-xl-4,body:lang(ku) .px-xl-4,body:lang(ur) .pr-xl-4,body:lang(ur) .px-xl-4{-webkit-padding-end:1.5rem!important;padding-inline-end:1.5rem!important}body:lang(fa) .pb-xl-4,body:lang(fa) .py-xl-4,body:lang(ar) .pb-xl-4,body:lang(ar) .py-xl-4,body:lang(az) .pb-xl-4,body:lang(az) .py-xl-4,body:lang(dv) .pb-xl-4,body:lang(dv) .py-xl-4,body:lang(he) .pb-xl-4,body:lang(he) .py-xl-4,body:lang(ku) .pb-xl-4,body:lang(ku) .py-xl-4,body:lang(ur) .pb-xl-4,body:lang(ur) .py-xl-4{padding-bottom:1.5rem!important}body:lang(fa) .pl-xl-4,body:lang(fa) .px-xl-4,body:lang(ar) .pl-xl-4,body:lang(ar) .px-xl-4,body:lang(az) .pl-xl-4,body:lang(az) .px-xl-4,body:lang(dv) .pl-xl-4,body:lang(dv) .px-xl-4,body:lang(he) .pl-xl-4,body:lang(he) .px-xl-4,body:lang(ku) .pl-xl-4,body:lang(ku) .px-xl-4,body:lang(ur) .pl-xl-4,body:lang(ur) .px-xl-4{-webkit-padding-start:1.5rem!important;padding-inline-start:1.5rem!important}body:lang(fa) .p-xl-5,body:lang(ar) .p-xl-5,body:lang(az) .p-xl-5,body:lang(dv) .p-xl-5,body:lang(he) .p-xl-5,body:lang(ku) .p-xl-5,body:lang(ur) .p-xl-5{padding:3rem!important}body:lang(fa) .pt-xl-5,body:lang(fa) .py-xl-5,body:lang(ar) .pt-xl-5,body:lang(ar) .py-xl-5,body:lang(az) .pt-xl-5,body:lang(az) .py-xl-5,body:lang(dv) .pt-xl-5,body:lang(dv) .py-xl-5,body:lang(he) .pt-xl-5,body:lang(he) .py-xl-5,body:lang(ku) .pt-xl-5,body:lang(ku) .py-xl-5,body:lang(ur) .pt-xl-5,body:lang(ur) .py-xl-5{padding-top:3rem!important}body:lang(fa) .pr-xl-5,body:lang(fa) .px-xl-5,body:lang(ar) .pr-xl-5,body:lang(ar) .px-xl-5,body:lang(az) .pr-xl-5,body:lang(az) .px-xl-5,body:lang(dv) .pr-xl-5,body:lang(dv) .px-xl-5,body:lang(he) .pr-xl-5,body:lang(he) .px-xl-5,body:lang(ku) .pr-xl-5,body:lang(ku) .px-xl-5,body:lang(ur) .pr-xl-5,body:lang(ur) .px-xl-5{-webkit-padding-end:3rem!important;padding-inline-end:3rem!important}body:lang(fa) .pb-xl-5,body:lang(fa) .py-xl-5,body:lang(ar) .pb-xl-5,body:lang(ar) .py-xl-5,body:lang(az) .pb-xl-5,body:lang(az) .py-xl-5,body:lang(dv) .pb-xl-5,body:lang(dv) .py-xl-5,body:lang(he) .pb-xl-5,body:lang(he) .py-xl-5,body:lang(ku) .pb-xl-5,body:lang(ku) .py-xl-5,body:lang(ur) .pb-xl-5,body:lang(ur) .py-xl-5{padding-bottom:3rem!important}body:lang(fa) .pl-xl-5,body:lang(fa) .px-xl-5,body:lang(ar) .pl-xl-5,body:lang(ar) .px-xl-5,body:lang(az) .pl-xl-5,body:lang(az) .px-xl-5,body:lang(dv) .pl-xl-5,body:lang(dv) .px-xl-5,body:lang(he) .pl-xl-5,body:lang(he) .px-xl-5,body:lang(ku) .pl-xl-5,body:lang(ku) .px-xl-5,body:lang(ur) .pl-xl-5,body:lang(ur) .px-xl-5{-webkit-padding-start:3rem!important;padding-inline-start:3rem!important}body:lang(fa) .m-xl-n1,body:lang(ar) .m-xl-n1,body:lang(az) .m-xl-n1,body:lang(dv) .m-xl-n1,body:lang(he) .m-xl-n1,body:lang(ku) .m-xl-n1,body:lang(ur) .m-xl-n1{margin:-.25rem!important}body:lang(fa) .mt-xl-n1,body:lang(fa) .my-xl-n1,body:lang(ar) .mt-xl-n1,body:lang(ar) .my-xl-n1,body:lang(az) .mt-xl-n1,body:lang(az) .my-xl-n1,body:lang(dv) .mt-xl-n1,body:lang(dv) .my-xl-n1,body:lang(he) .mt-xl-n1,body:lang(he) .my-xl-n1,body:lang(ku) .mt-xl-n1,body:lang(ku) .my-xl-n1,body:lang(ur) .mt-xl-n1,body:lang(ur) .my-xl-n1{margin-top:-.25rem!important}body:lang(fa) .mr-xl-n1,body:lang(fa) .mx-xl-n1,body:lang(ar) .mr-xl-n1,body:lang(ar) .mx-xl-n1,body:lang(az) .mr-xl-n1,body:lang(az) .mx-xl-n1,body:lang(dv) .mr-xl-n1,body:lang(dv) .mx-xl-n1,body:lang(he) .mr-xl-n1,body:lang(he) .mx-xl-n1,body:lang(ku) .mr-xl-n1,body:lang(ku) .mx-xl-n1,body:lang(ur) .mr-xl-n1,body:lang(ur) .mx-xl-n1{margin-right:-.25rem!important}body:lang(fa) .mb-xl-n1,body:lang(fa) .my-xl-n1,body:lang(ar) .mb-xl-n1,body:lang(ar) .my-xl-n1,body:lang(az) .mb-xl-n1,body:lang(az) .my-xl-n1,body:lang(dv) .mb-xl-n1,body:lang(dv) .my-xl-n1,body:lang(he) .mb-xl-n1,body:lang(he) .my-xl-n1,body:lang(ku) .mb-xl-n1,body:lang(ku) .my-xl-n1,body:lang(ur) .mb-xl-n1,body:lang(ur) .my-xl-n1{margin-bottom:-.25rem!important}body:lang(fa) .ml-xl-n1,body:lang(fa) .mx-xl-n1,body:lang(ar) .ml-xl-n1,body:lang(ar) .mx-xl-n1,body:lang(az) .ml-xl-n1,body:lang(az) .mx-xl-n1,body:lang(dv) .ml-xl-n1,body:lang(dv) .mx-xl-n1,body:lang(he) .ml-xl-n1,body:lang(he) .mx-xl-n1,body:lang(ku) .ml-xl-n1,body:lang(ku) .mx-xl-n1,body:lang(ur) .ml-xl-n1,body:lang(ur) .mx-xl-n1{margin-left:-.25rem!important}body:lang(fa) .m-xl-n2,body:lang(ar) .m-xl-n2,body:lang(az) .m-xl-n2,body:lang(dv) .m-xl-n2,body:lang(he) .m-xl-n2,body:lang(ku) .m-xl-n2,body:lang(ur) .m-xl-n2{margin:-.5rem!important}body:lang(fa) .mt-xl-n2,body:lang(fa) .my-xl-n2,body:lang(ar) .mt-xl-n2,body:lang(ar) .my-xl-n2,body:lang(az) .mt-xl-n2,body:lang(az) .my-xl-n2,body:lang(dv) .mt-xl-n2,body:lang(dv) .my-xl-n2,body:lang(he) .mt-xl-n2,body:lang(he) .my-xl-n2,body:lang(ku) .mt-xl-n2,body:lang(ku) .my-xl-n2,body:lang(ur) .mt-xl-n2,body:lang(ur) .my-xl-n2{margin-top:-.5rem!important}body:lang(fa) .mr-xl-n2,body:lang(fa) .mx-xl-n2,body:lang(ar) .mr-xl-n2,body:lang(ar) .mx-xl-n2,body:lang(az) .mr-xl-n2,body:lang(az) .mx-xl-n2,body:lang(dv) .mr-xl-n2,body:lang(dv) .mx-xl-n2,body:lang(he) .mr-xl-n2,body:lang(he) .mx-xl-n2,body:lang(ku) .mr-xl-n2,body:lang(ku) .mx-xl-n2,body:lang(ur) .mr-xl-n2,body:lang(ur) .mx-xl-n2{margin-right:-.5rem!important}body:lang(fa) .mb-xl-n2,body:lang(fa) .my-xl-n2,body:lang(ar) .mb-xl-n2,body:lang(ar) .my-xl-n2,body:lang(az) .mb-xl-n2,body:lang(az) .my-xl-n2,body:lang(dv) .mb-xl-n2,body:lang(dv) .my-xl-n2,body:lang(he) .mb-xl-n2,body:lang(he) .my-xl-n2,body:lang(ku) .mb-xl-n2,body:lang(ku) .my-xl-n2,body:lang(ur) .mb-xl-n2,body:lang(ur) .my-xl-n2{margin-bottom:-.5rem!important}body:lang(fa) .ml-xl-n2,body:lang(fa) .mx-xl-n2,body:lang(ar) .ml-xl-n2,body:lang(ar) .mx-xl-n2,body:lang(az) .ml-xl-n2,body:lang(az) .mx-xl-n2,body:lang(dv) .ml-xl-n2,body:lang(dv) .mx-xl-n2,body:lang(he) .ml-xl-n2,body:lang(he) .mx-xl-n2,body:lang(ku) .ml-xl-n2,body:lang(ku) .mx-xl-n2,body:lang(ur) .ml-xl-n2,body:lang(ur) .mx-xl-n2{margin-left:-.5rem!important}body:lang(fa) .m-xl-n3,body:lang(ar) .m-xl-n3,body:lang(az) .m-xl-n3,body:lang(dv) .m-xl-n3,body:lang(he) .m-xl-n3,body:lang(ku) .m-xl-n3,body:lang(ur) .m-xl-n3{margin:-1rem!important}body:lang(fa) .mt-xl-n3,body:lang(fa) .my-xl-n3,body:lang(ar) .mt-xl-n3,body:lang(ar) .my-xl-n3,body:lang(az) .mt-xl-n3,body:lang(az) .my-xl-n3,body:lang(dv) .mt-xl-n3,body:lang(dv) .my-xl-n3,body:lang(he) .mt-xl-n3,body:lang(he) .my-xl-n3,body:lang(ku) .mt-xl-n3,body:lang(ku) .my-xl-n3,body:lang(ur) .mt-xl-n3,body:lang(ur) .my-xl-n3{margin-top:-1rem!important}body:lang(fa) .mr-xl-n3,body:lang(fa) .mx-xl-n3,body:lang(ar) .mr-xl-n3,body:lang(ar) .mx-xl-n3,body:lang(az) .mr-xl-n3,body:lang(az) .mx-xl-n3,body:lang(dv) .mr-xl-n3,body:lang(dv) .mx-xl-n3,body:lang(he) .mr-xl-n3,body:lang(he) .mx-xl-n3,body:lang(ku) .mr-xl-n3,body:lang(ku) .mx-xl-n3,body:lang(ur) .mr-xl-n3,body:lang(ur) .mx-xl-n3{margin-right:-1rem!important}body:lang(fa) .mb-xl-n3,body:lang(fa) .my-xl-n3,body:lang(ar) .mb-xl-n3,body:lang(ar) .my-xl-n3,body:lang(az) .mb-xl-n3,body:lang(az) .my-xl-n3,body:lang(dv) .mb-xl-n3,body:lang(dv) .my-xl-n3,body:lang(he) .mb-xl-n3,body:lang(he) .my-xl-n3,body:lang(ku) .mb-xl-n3,body:lang(ku) .my-xl-n3,body:lang(ur) .mb-xl-n3,body:lang(ur) .my-xl-n3{margin-bottom:-1rem!important}body:lang(fa) .ml-xl-n3,body:lang(fa) .mx-xl-n3,body:lang(ar) .ml-xl-n3,body:lang(ar) .mx-xl-n3,body:lang(az) .ml-xl-n3,body:lang(az) .mx-xl-n3,body:lang(dv) .ml-xl-n3,body:lang(dv) .mx-xl-n3,body:lang(he) .ml-xl-n3,body:lang(he) .mx-xl-n3,body:lang(ku) .ml-xl-n3,body:lang(ku) .mx-xl-n3,body:lang(ur) .ml-xl-n3,body:lang(ur) .mx-xl-n3{margin-left:-1rem!important}body:lang(fa) .m-xl-n4,body:lang(ar) .m-xl-n4,body:lang(az) .m-xl-n4,body:lang(dv) .m-xl-n4,body:lang(he) .m-xl-n4,body:lang(ku) .m-xl-n4,body:lang(ur) .m-xl-n4{margin:-1.5rem!important}body:lang(fa) .mt-xl-n4,body:lang(fa) .my-xl-n4,body:lang(ar) .mt-xl-n4,body:lang(ar) .my-xl-n4,body:lang(az) .mt-xl-n4,body:lang(az) .my-xl-n4,body:lang(dv) .mt-xl-n4,body:lang(dv) .my-xl-n4,body:lang(he) .mt-xl-n4,body:lang(he) .my-xl-n4,body:lang(ku) .mt-xl-n4,body:lang(ku) .my-xl-n4,body:lang(ur) .mt-xl-n4,body:lang(ur) .my-xl-n4{margin-top:-1.5rem!important}body:lang(fa) .mr-xl-n4,body:lang(fa) .mx-xl-n4,body:lang(ar) .mr-xl-n4,body:lang(ar) .mx-xl-n4,body:lang(az) .mr-xl-n4,body:lang(az) .mx-xl-n4,body:lang(dv) .mr-xl-n4,body:lang(dv) .mx-xl-n4,body:lang(he) .mr-xl-n4,body:lang(he) .mx-xl-n4,body:lang(ku) .mr-xl-n4,body:lang(ku) .mx-xl-n4,body:lang(ur) .mr-xl-n4,body:lang(ur) .mx-xl-n4{margin-right:-1.5rem!important}body:lang(fa) .mb-xl-n4,body:lang(fa) .my-xl-n4,body:lang(ar) .mb-xl-n4,body:lang(ar) .my-xl-n4,body:lang(az) .mb-xl-n4,body:lang(az) .my-xl-n4,body:lang(dv) .mb-xl-n4,body:lang(dv) .my-xl-n4,body:lang(he) .mb-xl-n4,body:lang(he) .my-xl-n4,body:lang(ku) .mb-xl-n4,body:lang(ku) .my-xl-n4,body:lang(ur) .mb-xl-n4,body:lang(ur) .my-xl-n4{margin-bottom:-1.5rem!important}body:lang(fa) .ml-xl-n4,body:lang(fa) .mx-xl-n4,body:lang(ar) .ml-xl-n4,body:lang(ar) .mx-xl-n4,body:lang(az) .ml-xl-n4,body:lang(az) .mx-xl-n4,body:lang(dv) .ml-xl-n4,body:lang(dv) .mx-xl-n4,body:lang(he) .ml-xl-n4,body:lang(he) .mx-xl-n4,body:lang(ku) .ml-xl-n4,body:lang(ku) .mx-xl-n4,body:lang(ur) .ml-xl-n4,body:lang(ur) .mx-xl-n4{margin-left:-1.5rem!important}body:lang(fa) .m-xl-n5,body:lang(ar) .m-xl-n5,body:lang(az) .m-xl-n5,body:lang(dv) .m-xl-n5,body:lang(he) .m-xl-n5,body:lang(ku) .m-xl-n5,body:lang(ur) .m-xl-n5{margin:-3rem!important}body:lang(fa) .mt-xl-n5,body:lang(fa) .my-xl-n5,body:lang(ar) .mt-xl-n5,body:lang(ar) .my-xl-n5,body:lang(az) .mt-xl-n5,body:lang(az) .my-xl-n5,body:lang(dv) .mt-xl-n5,body:lang(dv) .my-xl-n5,body:lang(he) .mt-xl-n5,body:lang(he) .my-xl-n5,body:lang(ku) .mt-xl-n5,body:lang(ku) .my-xl-n5,body:lang(ur) .mt-xl-n5,body:lang(ur) .my-xl-n5{margin-top:-3rem!important}body:lang(fa) .mr-xl-n5,body:lang(fa) .mx-xl-n5,body:lang(ar) .mr-xl-n5,body:lang(ar) .mx-xl-n5,body:lang(az) .mr-xl-n5,body:lang(az) .mx-xl-n5,body:lang(dv) .mr-xl-n5,body:lang(dv) .mx-xl-n5,body:lang(he) .mr-xl-n5,body:lang(he) .mx-xl-n5,body:lang(ku) .mr-xl-n5,body:lang(ku) .mx-xl-n5,body:lang(ur) .mr-xl-n5,body:lang(ur) .mx-xl-n5{margin-right:-3rem!important}body:lang(fa) .mb-xl-n5,body:lang(fa) .my-xl-n5,body:lang(ar) .mb-xl-n5,body:lang(ar) .my-xl-n5,body:lang(az) .mb-xl-n5,body:lang(az) .my-xl-n5,body:lang(dv) .mb-xl-n5,body:lang(dv) .my-xl-n5,body:lang(he) .mb-xl-n5,body:lang(he) .my-xl-n5,body:lang(ku) .mb-xl-n5,body:lang(ku) .my-xl-n5,body:lang(ur) .mb-xl-n5,body:lang(ur) .my-xl-n5{margin-bottom:-3rem!important}body:lang(fa) .ml-xl-n5,body:lang(fa) .mx-xl-n5,body:lang(ar) .ml-xl-n5,body:lang(ar) .mx-xl-n5,body:lang(az) .ml-xl-n5,body:lang(az) .mx-xl-n5,body:lang(dv) .ml-xl-n5,body:lang(dv) .mx-xl-n5,body:lang(he) .ml-xl-n5,body:lang(he) .mx-xl-n5,body:lang(ku) .ml-xl-n5,body:lang(ku) .mx-xl-n5,body:lang(ur) .ml-xl-n5,body:lang(ur) .mx-xl-n5{margin-left:-3rem!important}body:lang(fa) .m-xl-auto,body:lang(ar) .m-xl-auto,body:lang(az) .m-xl-auto,body:lang(dv) .m-xl-auto,body:lang(he) .m-xl-auto,body:lang(ku) .m-xl-auto,body:lang(ur) .m-xl-auto{margin:auto!important}body:lang(fa) .mt-xl-auto,body:lang(fa) .my-xl-auto,body:lang(ar) .mt-xl-auto,body:lang(ar) .my-xl-auto,body:lang(az) .mt-xl-auto,body:lang(az) .my-xl-auto,body:lang(dv) .mt-xl-auto,body:lang(dv) .my-xl-auto,body:lang(he) .mt-xl-auto,body:lang(he) .my-xl-auto,body:lang(ku) .mt-xl-auto,body:lang(ku) .my-xl-auto,body:lang(ur) .mt-xl-auto,body:lang(ur) .my-xl-auto{margin-top:auto!important}body:lang(fa) .mr-xl-auto,body:lang(fa) .mx-xl-auto,body:lang(ar) .mr-xl-auto,body:lang(ar) .mx-xl-auto,body:lang(az) .mr-xl-auto,body:lang(az) .mx-xl-auto,body:lang(dv) .mr-xl-auto,body:lang(dv) .mx-xl-auto,body:lang(he) .mr-xl-auto,body:lang(he) .mx-xl-auto,body:lang(ku) .mr-xl-auto,body:lang(ku) .mx-xl-auto,body:lang(ur) .mr-xl-auto,body:lang(ur) .mx-xl-auto{margin-right:auto!important}body:lang(fa) .mb-xl-auto,body:lang(fa) .my-xl-auto,body:lang(ar) .mb-xl-auto,body:lang(ar) .my-xl-auto,body:lang(az) .mb-xl-auto,body:lang(az) .my-xl-auto,body:lang(dv) .mb-xl-auto,body:lang(dv) .my-xl-auto,body:lang(he) .mb-xl-auto,body:lang(he) .my-xl-auto,body:lang(ku) .mb-xl-auto,body:lang(ku) .my-xl-auto,body:lang(ur) .mb-xl-auto,body:lang(ur) .my-xl-auto{margin-bottom:auto!important}body:lang(fa) .ml-xl-auto,body:lang(fa) .mx-xl-auto,body:lang(ar) .ml-xl-auto,body:lang(ar) .mx-xl-auto,body:lang(az) .ml-xl-auto,body:lang(az) .mx-xl-auto,body:lang(dv) .ml-xl-auto,body:lang(dv) .mx-xl-auto,body:lang(he) .ml-xl-auto,body:lang(he) .mx-xl-auto,body:lang(ku) .ml-xl-auto,body:lang(ku) .mx-xl-auto,body:lang(ur) .ml-xl-auto,body:lang(ur) .mx-xl-auto{margin-left:auto!important}}body:lang(fa) .dropdown-menu,body:lang(ar) .dropdown-menu,body:lang(az) .dropdown-menu,body:lang(dv) .dropdown-menu,body:lang(he) .dropdown-menu,body:lang(ku) .dropdown-menu,body:lang(ur) .dropdown-menu{text-align:right}body:lang(fa) .text-right,body:lang(ar) .text-right,body:lang(az) .text-right,body:lang(dv) .text-right,body:lang(he) .text-right,body:lang(ku) .text-right,body:lang(ur) .text-right{text-align:left!important}body:lang(fa) pre,body:lang(ar) pre,body:lang(az) pre,body:lang(dv) pre,body:lang(he) pre,body:lang(ku) pre,body:lang(ur) pre{text-align:left;direction:ltr}body:lang(fa) .td-rss-button,body:lang(ar) .td-rss-button,body:lang(az) .td-rss-button,body:lang(dv) .td-rss-button,body:lang(he) .td-rss-button,body:lang(ku) .td-rss-button,body:lang(ur) .td-rss-button{left:1rem!important;right:auto!important}body:lang(fa){font-family:vazir,open sans,-apple-system,BlinkMacSystemFont,segoe ui,Roboto,helvetica neue,Arial,sans-serif,apple color emoji,segoe ui emoji,segoe ui symbol}body:lang(he){font-family:rubik,open sans,-apple-system,BlinkMacSystemFont,segoe ui,Roboto,helvetica neue,Arial,sans-serif,apple color emoji,segoe ui emoji,segoe ui symbol}body:lang(ar){font-family:tajawal,open sans,-apple-system,BlinkMacSystemFont,segoe ui,Roboto,helvetica neue,Arial,sans-serif,apple color emoji,segoe ui emoji,segoe ui symbol} \ No newline at end of file diff --git a/docs/typescript/sitemap.xml b/docs/typescript/sitemap.xml new file mode 100644 index 0000000..36abe16 --- /dev/null +++ b/docs/typescript/sitemap.xml @@ -0,0 +1,42 @@ + + + + https://yahoo.github.io/bgdocs/docs/typescript/quickstart/ + 2022-02-01T19:27:09-08:00 + + https://yahoo.github.io/bgdocs/docs/typescript/ + 2022-02-01T19:27:09-08:00 + + https://yahoo.github.io/bgdocs/docs/typescript/why-behavior-graph/ + 2022-02-02T11:01:27-08:00 + + https://yahoo.github.io/bgdocs/docs/typescript/code-example/ + 2022-02-02T11:01:27-08:00 + + https://yahoo.github.io/bgdocs/docs/typescript/api/ + 2022-02-01T19:27:09-08:00 + + https://yahoo.github.io/bgdocs/docs/typescript/tutorials/ + 2022-02-01T19:27:09-08:00 + + https://yahoo.github.io/bgdocs/docs/typescript/relatedwork/ + 2022-02-01T19:27:09-08:00 + + https://yahoo.github.io/bgdocs/docs/typescript/questions/ + 2022-02-01T19:27:09-08:00 + + https://yahoo.github.io/bgdocs/docs/typescript/categories/ + + https://yahoo.github.io/bgdocs/docs/typescript/tags/ + + https://yahoo.github.io/bgdocs/docs/typescript/tutorials/tutorial-1/ + 2022-02-01T19:27:09-08:00 + + https://yahoo.github.io/bgdocs/docs/typescript/tutorials/tutorial-2/ + 2022-02-02T11:01:27-08:00 + + https://yahoo.github.io/bgdocs/docs/typescript/tutorials/tutorial-3/ + 2022-02-02T11:01:27-08:00 + + diff --git a/docs/typescript/tags/index.html b/docs/typescript/tags/index.html new file mode 100644 index 0000000..994fe8e --- /dev/null +++ b/docs/typescript/tags/index.html @@ -0,0 +1,143 @@ + + + + + + + + + + + + + + + + + + + + + +Tags | Behavior Graph + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+
+
+ +
+
+

Tags

+ + + + + + + +
+
+ +
+ +
+
+
+
+ +
+
+ +
+
+ © 2022 Yahoo All Rights Reserved + + + + +
+
+
+
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/typescript/tags/index.xml b/docs/typescript/tags/index.xml new file mode 100644 index 0000000..575a50d --- /dev/null +++ b/docs/typescript/tags/index.xml @@ -0,0 +1,17 @@ + + + Behavior Graph – Tags + https://yahoo.github.io/bgdocs/docs/typescript/tags/ + Recent content in Tags on Behavior Graph + Hugo -- gohugo.io + + + + + + + + + + + diff --git a/docs/typescript/tutorials/_print/index.html b/docs/typescript/tutorials/_print/index.html new file mode 100644 index 0000000..a11fe7f --- /dev/null +++ b/docs/typescript/tutorials/_print/index.html @@ -0,0 +1,1526 @@ + + + + + + + + + + + + + + + + + + + + + + +Tutorials | Behavior Graph + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+
+
+
+
+ + + + + +
+
+

+This is the multi-page printable view of this section. +Click here to print. +

+Return to the regular view of this page. +

+
+ + + +

Tutorials

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

1 - Tutorial 1 - Basics

+ +

Here we will introduce the essentials to get you started quickly using Behavior Graph.

+

The recommended way to get started is to use our preconfigured tutorial site.

+

If you prefer to set up your own environment please see the Quick Start page. +Make sure to open up the Javascript console. +That is where we will generate our output.

+

Hello, World!

+

Type in the following into the editor. +You will gain more by typing it, as it forces you to think about each line.

+
import * as bg from "https://cdn.skypack.dev/behavior-graph";
+
+let g = new bg.Graph();
+
+class HelloExtent extends bg.Extent {
+  constructor(graph) {
+    super(graph);
+    
+    this.person = this.state("Nobody");
+    this.behavior()
+      .demands(this.person)
+      .runs(() => {
+        console.log("Hello, " + this.person.value + "!");
+      });
+  }
+}
+
+let e = new HelloExtent(g);
+
+e.addToGraphWithAction();
+
+g.action(() => {
+  e.person.update("World");
+});
+

Run the code. +In the console you should see

+
"Hello, World!"
+

The Parts

+

Let’s review this in pieces.

+
import * as bg from "https://cdn.skypack.dev/behavior-graph";
+

This is a standard Javascript import. +You may need to adjust it depending on your Javascript environment which is beyond the scope of this tutorial. +Behavior Graph is distributed though NPM and is available through a number of downstream CDNs. +See the Quick Start page for more information. +Note that Behavior Graph is imported as bg here. +We will reference that in a few places in the tutorial. +Your import name may be different.

+
let g = new bg.Graph();
+

You must create an instance of a Graph. +You may have more than one instance, but all Behavior Graph elements are associated with a specific instance.

+
class HelloExtent extends bg.Extent {
+  constructor(graph) {
+    super(graph);
+

You will modularize your Behavior Graph code into Extents. +You do this by extending the built in Extent class and passing it your Graph instance in the constructor. +Extents collect Behaviors and Resources together with the same lifetime.

+
    this.person = this.state("Nobody");
+

person is a Resource. +Resources are containers for information. +This specifically is a State resource. +State resources contain persistent information, i.e. it may be used in the future. +You will define state resources as properties on your Extent subclass and create them with the .state() factory method. +State resources always have an initial value. +Our person resource has an initial value of "Nobody".

+
    this.behavior()
+      .demands(this.person)
+      .runs(() => {
+        console.log("Hello, " + this.person.value + "!");
+      });
+

This is a Behavior. +Behaviors are units of functionality. +We create them with the .behavior() factory method that uses a fluent BehaviorBuilder API.

+

This behavior has two parts. +The .demands() clause states that this behavior depends on the resource person.

+

The .runs() clause is the code that gets run whenever one (or more) of the demands is updated (has new information). +This one prints our greeting using this.person.value. +The .value property returns the contents of our person state resource. +A behavior must demand a resource in order to access its .value property. +(It can also access it if it supplies the resource as well.)

+
let e = new HelloExtent(g);
+e.addToGraphWithAction();
+

We will need to create an instance of our HelloExtent in order to add it to the graph. +Then we call .addToGraphWithAction() which adds the HelloExtent’s resource and behavior to our graph. +They will not perform any work until their extent has been added.

+
g.action(() => {
+  e.person.update("World");
+});
+

Here we create a new Action using .action() on our Graph instance. +Action blocks are how we introduce new information from the outside. +In this case, we are providing the person’s name by calling .update() on our person state resource.

+

How it works

+

This call to .action() will start a series of steps.

+
    +
  1. It will run the anonymous function given as a parameter.
  2. +
  3. e.person.update() will tell the graph to mark any demanding behaviors as activated. +In this case there is the only one demanding behavior.
  4. +
  5. The anonymous function will complete.
  6. +
  7. The graph will call the runs block on the one activated behavior.
  8. +
  9. That runs block prints out “Hello, World!” by accessing the .value of person which is the value we passed into the .update() method.
  10. +
  11. The .action() method completes and the program continues.
  12. +
+

All of these steps together make up a single Behavior Graph Event.

+

Doing More

+

While this may seem like a tedious implementation of “Hello, World”, we have already established a foundation that will let this program grow to arbitrary complexity. +The computer can use these components to support us throughout the development process.

+

Let’s introduce a second reason why we may need to print our greeting.

+

The highlighted lines will always be the new or updated lines

+
    this.person = this.state("Nobody");
+    this.greeting = this.state("Greetings");
+    this.behavior()
+      .demands(this.person, this.greeting)
+      .runs(() => {
+        console.log(this.greeting.value + ", " + this.person.value + "!");
+      });
+

First we create a second state resource, greeting. +Then we add greeting as an additional demand. +We must add it as a demand because we access its .value property. +Behavior Graph will raise an error if we do not. +This explicitness is by design. +Finally we modify our message to use greeting.value.

+

When we run our program now it should produce

+
"Greetings, World!"
+

If we want to get back to our original message we can add more to our action.

+
g.action(() => {
+  e.person.update("World");
+  e.greeting.update("Hello");
+});
+

Now we have

+
"Hello, World!"
+

Multiple Updates

+

This illustrates an important distinction between Behavior Graph and many reactive libraries. +Our behavior demands multiple resources. +That means whenever either person or greeting or both update our behavior should run. +However it doesn’t run immediately, it is only activated.

+

Inside our action we update both person and greeting. +Our behavior that demands them will not run until the entire action block has completed. +All updates inside a single action are treated as if they happened at the same time. +This means our behavior runs only once.

+

We aren’t required to provide both just because we demand both. +State resources persist their value from action to action. +Let’s add an additional action to see this.

+
g.action(() => {
+  e.person.update("World");
+  e.greeting.update("Hello");
+});
+g.action(() => {
+  e.greeting.update("Goodbye");
+});
+

Now in our console it should print

+
"Hello, World!"
+"Goodbye, World!"
+

“World” persisted into the second event. While “Goodbye” replaced the previous greeting.

+

Moments

+

Not all information persists. +Sometimes things just happen. +A button press is a typical example. +We can model this information with Moment resources.

+
    this.person = this.state("Nobody");
+    this.greeting = this.state("Greetings");
+    this.button = this.moment();
+    this.behavior()
+      .demands(this.person, this.greeting, this.button)
+      .runs(() => {
+        if (this.button.justUpdated) {
+          console.log(this.greeting.value + ", " + this.person.value + "!");
+        }
+      });
+

First we create a button resource. +We create it with a .moment() factory method on our Extent subclass. +Then we add it to our behavior’s list of demands so it runs when button updates.

+

Inside our runs block, we’ve gated our log statement by checking against button.justUpdated. +This will be true only if some other part of our code called button.update() during the same event.

+

Press the Button

+

If you run the program now you will get no output. +This is because we only update the person and greeting resources and our log statement only runs when button.justUpdated is true.

+

So lets add some additional lines to simulate a button press.

+
g.action(() => {
+  e.person.update("World");
+  e.greeting.update("Hello");
+});
+g.action(() => {
+  e.greeting.update("Goodbye");
+});
+g.action(() => {
+  e.button.update();
+});
+

Now our program outputs:

+
"Goodbye, World!"
+

The first two actions only update the state resources. +Our behavior is run but the if (this.button.justUpdated) check prevents anything from happening. +The third action causes the behavior to run as well. +This time the if check passes and it logs the message based on prior updates.

+

Of course they don’t need to be in separate actions.

+
g.action(() => {
+  e.button.update();
+  e.greeting.update("Nevermind");
+});
+

Will output:

+
"Nevermind, World!"
+

The message changed because both button updated as well as greeting in that same action. +The order in which they were updated inside the action is irrelevant to any demanding behaviors.

+

A Graph

+

With only one behavior, it is difficult to call it a behavior graph. +The real power of Behavior Graph comes with the ability to incrementally introduce related functionality. +Behaviors will often depend on information provided by other behaviors.

+

Supplies

+

Imagine, for security sake, that we would like to introduce logging into our “Hello, World” program.

+
    this.button = this.moment();
+    this.message = this.state(null);
+    this.behavior()
+      .supplies(this.message)
+      .demands(this.person, this.greeting, this.button)
+      .runs(() => {
+        this.message.update(this.greeting.value + ", " + this.person.value + "!");
+        if (this.button.justUpdated) {
+          console.log(this.message.value);
+        }
+      });
+

We add a new state resource, message, to save the current message. +We add this resource to a new supplies clause of our behavior definition with .supplies(). +Supplies are resources that this behavior is solely responsible for. +It means that a behavior can both read a resource’s .value and .update() it as well.

+

We call message.update() with the text contents of the greeting to save them for later.

+ + + + +

Logging Behavior

+

We can introduce the logging functionality by adding an additional behavior.

+
        if (this.button.justUpdated) {
+          console.log(this.message.value);
+        }
+      });
+      
+    this.behavior()
+      .demands(this.message)
+      .runs(() => {
+        console.log("Message changed to: " + this.message.value);
+      });
+

This new behavior demands message. +This means it will run whenever message updates. +Our output shows this result:

+
"Message changed to: Hello, World!"
+"Message changed to: Goodbye, World!"
+"Nevermind, World!"
+"Message changed to: Nevermind, World!"
+

As you can see our new logging behavior runs and generates output each time the message changes.

+

Events

+

In Behavior Graph we call a single pass through the graph (from the start of an action to the last output) an Event. +Our current output is the result of three events.

+

First Event:

+
graph LR
+  a["Action:<br />person=>World<br />greeting=>Hello"] --> b["Behavior 1:<br />message=>Hello, World!"] --> c["Behavior 2:<br />message change logged"]
+

Second Event:

+
graph LR
+  a["Action:<br />greeting=>Goodbye"] --> b["Behavior 1:<br />message=>Goodbye, World!"] --> c["Behavior 2:<br />message change logged"]
+

Third Event:

+
graph LR
+  a["Action:<br />button updates<br />greeting=>Nevermind"] --> b["Behavior 1:<br />message=>Nevermind, World!<br />message printed"] --> c["Behavior 2:<br />message change logged"]
+

The Same Event

+

Every time a resource is updated, it is assigned the current event. +So in the First Event example above, when person and greeting update, they get pointers to that same event in their .event property. +Then when message updates in the first behavior it also gets a pointer to this same event.

+

We can access this event inside any behavior that we demand (or supply). +This can use this to append a timestamp to our log messages.

+
    this.behavior()
+      .demands(this.message)
+      .runs(() => {
+        console.log("Message changed to: " + this.message.value + " : " + this.message.event.timestamp);
+      });
+

You should now see something similar to the lines below

+
"Message changed to: Hello, World! : Fri Jan 28 2022 16:43:43 GMT-0800"
+"Message changed to: Goodbye, World! : Fri Jan 28 2022 16:43:43 GMT-0800"
+"Nevermind, World!"
+"Message changed to: Nevermind, World! : Fri Jan 28 2022 16:43:43 GMT-0800"
+

What Just Happened?

+

Using .justUpdated is a powerful tool for organizing our code into related functionality. +We will add additional logging to see how this works. +First we will track when we send the message.

+
    this.message = this.state(null);
+    this.sentMessage = this.moment();
+    this.behavior()
+      .supplies(this.message, this.sentMessage)
+      .demands(this.person, this.greeting, this.button)
+      .runs(() => {
+        this.message.update(this.greeting.value + ", " + this.person.value + "!");
+        if (this.button.justUpdated) {
+          console.log(this.message.value);
+          this.sentMessage.update();
+        }
+      });
+

We create a moment resource for sentMessage. +Sending the message is a one off action, so we keep track of that with a moment. +We will be calling .update() on sentMessage so we need to add it to the list of supplies. +We call this.sentMessage.update() right after the console.log call to track when we actually print out our message.

+

Note that a behavior can supply more than one resource. +This is a common pattern that lets us group related logic together without having to jump through hoops to avoid duplication.

+

Next we modify our logging message to demand this additional resource.

+
    this.behavior()
+      .demands(this.message, this.sentMessage)
+      .runs(() => {
+        if (this.message.justUpdated) {
+          console.log("Message changed to: " + this.message.value + " : " + this.message.event.timestamp);      
+        }
+        if (this.sentMessage.justUpdated) {
+          console.log("Message sent: " + this.message.value + " : " + this.message.event.timestamp);
+        }
+      });
+

This behavior now demands sentMessage which means it will run whenever that resource is updated. +Inside our run block we check to see which resource was updated and generate the correct log message. +It may be the case that either one or both is updated.

+

You will find yourself using this “what just happened?” pattern in many of your behaviors.

+

Running your program should looks like this:

+
"Message changed to: Hello, World! : Sat Jan 29 2022 08:33:05 GMT-0800"
+"Message changed to: Goodbye, World! : Sat Jan 29 2022 08:33:05 GMT-0800"
+"Nevermind, World!"
+"Message changed to: Nevermind, World! : Sat Jan 29 2022 08:33:05 GMT-0800"
+"Message sent: Nevermind, World! : Sat Jan 29 2022 08:33:05 GMT-0800"
+

Challenge

+

Can you introduce a single resource that turns on or off our newly added logging? +Try to do this challenge before looking at the answer.

+

Here’s some hints:

+
    +
  • Try adding a state resource.
  • +
  • You’ll need to demand it in a behavior and introduce some additional logic.
  • +
+

Answer

+
    this.sentMessage = this.moment();
+    this.loggingEnabled = this.state(true);
+    this.behavior()
+      .supplies(this.message, this.sentMessage)
+      .demands(this.person, this.greeting, this.button)
+      .runs(() => {
+        this.message.update(this.greeting.value + ", " + this.person.value + "!");
+        if (this.button.justUpdated) {
+          console.log(this.message.value);
+          this.sentMessage.update();
+        }
+      });
+      
+    this.behavior()
+      .demands(this.message, this.sentMessage, this.loggingEnabled)
+      .runs(() => {
+        if (this.loggingEnabled.value) {
+          if (this.message.justUpdated) {
+            console.log("Message changed to: " + this.message.value + " : " + this.message.event.timestamp);      
+          }
+          if (this.sentMessage.justUpdated) {
+            console.log("Message sent: " + this.message.value + " : " + this.message.event.timestamp);
+          }
+        }
+      });
+

loggingEnabled is our new resource. +We want it to persist so we use a state resource. +It defaults to true meaning logging is on.

+

We then need to demand it inside our logging behavior in order to access its .value property. +If we try to access .value without demanding it, Behavior Graph will raise an error.

+

We can modify our last action to see it work.

+
g.action(() => {
+  e.button.update();
+  e.greeting.update("Nevermind");
+  e.loggingEnabled.update(false);
+});
+

After adding this additional line, running our code looks like this.

+
"Message changed to: Hello, World! : Sat Jan 29 2022 08:39:43 GMT-0800"
+"Message changed to: Goodbye, World! : Sat Jan 29 2022 08:39:43 GMT-0800"
+"Nevermind, World!"
+

We no longer log the last two messages because logging was turned off in the same action. +Notice how even though loggingEnabled.update(false) comes after our updates, we still disable logging for the same event. +If you were to do this without Behavior Graph, using status quo method calls and property updates, you would need to ensure that loggingEnabled changes to false before the other updates. +It would be a different result if you updated it after. +The ability to remove the hidden complexity that comes with sequencing is a programming superpower. +Behavior Graph gives you this feature for free.

+

Ordering Resources

+

You may notice that although .loggingEnabled is a demand, we don’t actually need it to to be a reason for our logging behavior to run. +We only need to check its .value. +Behavior Graph lets us lighten this constraint.

+
    this.behavior()
+      .demands(this.message, this.sentMessage, this.loggingEnabled.order)
+      .runs(() => {
+        if (this.loggingEnabled.value) {
+          if (this.message.justUpdated) {
+

We can add .order to any resource inside our demands clause. +When we do this, updating that resource will not activate this behavior. +This can give us some additional accuracy when specifying how our behaviors are linked.

+

Complete

+

Congratulations! You have completed this first tutorial. +You can see the finished tutorial code here.

+

While you may feel that there were many new concepts introduced, we have already covered the majority of them. +You will find they come naturally with some practice. +The remaining tutorials give you a taste for how Behavior Graph works inside real interactive programs.

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

2 - Tutorial 2 - IO

+ +

This tutorial will show how Behavior Graph interacts with real inputs and outputs to produce a working application. +In this case we will build the control system for a thermostat, the device in your house that controls the heat.

+

Thermostat

+

This simplified thermostat has two buttons, Up and Down for raising and lowering the desired temperature. +It also periodically gets external updates of the current temperature. +If the desired temperature is above the current temperature, we will turn on the heat. +And once they are the same, the heat will turn off.

+

Initial Code

+

We have created a starter project using JSFiddle. +You should use that for this tutorial. +It has some simple HTML/CSS to represent the Thermostat’s user interface. +If you wish to use your own environment you will need to copy the HTML and CSS from this JSFiddle site into your own.

+

The initial setup code has been provided for you.

+
import * as bg from "https://cdn.skypack.dev/behavior-graph";
+
+class Thermostat extends bg.Extent {
+  constructor(graph) {
+    super(graph);
+  }
+}
+
+let graph = new bg.Graph();
+let tm = new Thermostat(graph);
+tm.addToGraphWithAction();
+

The bulk of our application will exist inside our Thermostat subclass of Extent.

+

Desired Temperature

+

The first part of our logic will focus on setting the desired temperature. +The related elements look something like this.

+

Desired Temperature

+

First we need a state resource to track our desired temperature and a behavior to supply it.

+
class Thermostat extends bg.Extent {
+  constructor(graph) {
+    super(graph);
+
+    this.desiredTemperature = this.state(60);
+    this.behavior()
+      .supplies(this.desiredTemperature)
+      .runs(() => {
+      	// desired temperature logic will go here
+      });
+  }
+}
+

desiredTemperature is a state resource with an initial value of 60. +We want a state resource because it is information we intend to use in the future. +Our new behavior supplies this resource because we plan on calling desiredTemperature.update() inside the runs block.

+

Button Presses

+

Our thermostat will need to respond to the button press events that come from our HTML buttons.

+
    super(graph);
+
+    this.up = this.moment();
+    document.querySelector('#up').addEventListener('click', () => {
+      this.up.updateWithAction();
+    });
+
+    this.desiredTemperature = this.state(60);
+

We create an up moment resource to track when the Up button is pressed. +Then we use standard DOM manipulation code to respond to the HTML click event. +We call this.up.updateWithAction() to track this event in our moment resource.

+

.updateWithAction() is syntactic sugar for creating a new action and calling .update(). +It is the same as if we typed this instead:

+
    document.querySelector('#up').addEventListener('click', () => {
+      this.graph.action(() => {
+        this.up.update();
+      });
+    });
+

Responding to the Button

+

We need to modify our behavior to respond to this update.

+
    this.desiredTemperature = this.state(60);
+    this.behavior()
+      .supplies(this.desiredTemperature)
+      .demands(this.up)
+      .runs(() => {
+        if (this.up.justUpdated) {
+          this.desiredTemperature.update(this.desiredTemperature.value + 1);
+        }
+      });
+

We add up to our list of demands. +This ensures that this behavior activates whenever up is updated. +Inside the run block we check for .justUpdated. +If so, we update the desiredTemperature by incrementing it from its previous .value.

+ + + + +

These rules are essential to allowing Behavior Graph to ensure your resources are always in a consistent state.

+

Output

+

At this point our desiredTemperature changes when you press the Up button. +But we don’t update the display. +We add that here.

+
    this.behavior()
+      .supplies(this.desiredTemperature)
+      .demands(this.up)
+      .runs(() => {
+        if (this.up.justUpdated) {
+          this.desiredTemperature.update(this.desiredTemperature.value + 1);
+        }
+        this.sideEffect(() => {
+          document.querySelector('#desiredTemperature').innerText = this.desiredTemperature.value;
+        });
+      });
+

This behavior creates a Side Effect block. +Inside that block we use standard DOM methods to update the temperature. +Now if you run this and click on the Up button you will see the temperature field appear and increment.

+

Side effects are the correct way to generate output from inside a behavior. +Although a side effect is created inside a behavior, it will only run after all other behaviors have completed running. +This ensures that all our internal state has settled before calling code that may potentially access it.

+

Side effects do not have a restriction on what resources they can access, unlike the behavior in which they are defined.

+

Down

+

We can add the handling for our Down button in a similar way.

+
    this.up = this.moment();
+    document.querySelector('#up').addEventListener('click', () => {
+      this.up.updateWithAction();
+    });
+
+    this.down = this.moment();
+    document.querySelector('#down').addEventListener('click', () => {
+      this.down.updateWithAction();
+    });
+

And modify our behavior to respond.

+
    this.behavior()
+      .supplies(this.desiredTemperature)
+      .demands(this.up, this.down)
+      .runs(() => {
+        if (this.up.justUpdated) {
+          this.desiredTemperature.update(this.desiredTemperature.value + 1);
+        } else if (this.down.justUpdated) {
+          this.desiredTemperature.update(this.desiredTemperature.value - 1);        
+        }
+        this.sideEffect(() => {
+

Run the program. +Clicking on the Up and Down buttons should now move the desired temperature display up and down.

+

AddedToGraph

+

You may have noticed that the desired temperature display doesn’t show up until after we’ve tapped on one of the buttons. +This is because our behavior only runs when one of its demands is updated. +What we would like to do is also run it once at the beginning.

+
    this.behavior()
+      .supplies(this.desiredTemperature)
+      .demands(this.up, this.down, this.addedToGraph)
+      .runs(() => {
+        if (this.up.justUpdated) {
+

We add the this.addedToGraph resource to our list of demands. +Now when you run the code you will see that the temperature appears at the beginning.

+

addedToGraph is a built in state resource that is part of every Extent. +It is updated to true when the Extent is added to the graph. +Just like other resources you can demand it to get a behavior to run at the beginning. +And you can check it’s .justUpdated property to specialize your logic when necessary.

+

Heat

+

Now we need to introduce a separate bit of functionality to control the heating equipment. +This logic compares the current temperature to the desired temperature and turns on or off the heating equipment accordingly.

+

Current Temperature

+

Current Temperature

+

First we need a resource to track the current temperature,

+
    this.desiredTemperature = this.state(60);
+    this.currentTemperature = this.state(60);
+

and a new behavior to update the UI when that resource updates.

+
        this.sideEffect(() => {
+          document.querySelector('#desiredTemperature').innerText = this.desiredTemperature.value;
+        });
+      });
+      
+    this.behavior()
+      .demands(this.currentTemperature, this.addedToGraph)
+      .runs(() => {
+        this.sideEffect(() => {
+          document.querySelector('#currentTemperatureDisplay').innerText = this.currentTemperature.value;
+        });
+      });
+

Like with desiredTemperature this behavior runs whenever currentTemperature updates as well as once at the beginning. +It uses a side effect to update our UI.

+

Heat On

+

Next we need a resource to track if the heat is on or not.

+
    this.desiredTemperature = this.state(60);
+    this.currentTemperature = this.state(60);
+    this.heatOn = this.state(false);
+

By default the heatOn state resource is false indicating that it is off.

+
      .runs(() => {
+        this.sideEffect(() => {
+          document.querySelector('#currentTemperatureDisplay').innerText = this.currentTemperature.value;
+        });
+      });
+
+    this.behavior()
+      .supplies(this.heatOn)
+      .demands(this.currentTemperature, this.desiredTemperature)
+      .runs(() => {
+        let heatOn = this.desiredTemperature.value > this.currentTemperature.value;
+        this.heatOn.update(heatOn);
+      });
+

Here we add another new behavior. +It is responsible for updating heatOn so we add it as a supply. +It uses both currentTemperature and desiredTemperature for its logic, so both are demands. +When it runs, it updates heatOn to true if our currentTemperature is too low.

+

Heat Display

+

We want our display to update alongside the heatOn. +So we add that logic to our new behavior.

+
    this.behavior()
+      .supplies(this.heatOn)
+      .demands(this.currentTemperature, this.desiredTemperature, this.addedToGraph)
+      .runs(() => {
+        let heatOn = this.desiredTemperature.value > this.currentTemperature.value;
+        this.heatOn.update(heatOn);
+        this.sideEffect(() => {
+          document.querySelector('#heatStatus').innerText = this.heatOn.value ? "On" : "Off"
+        });
+      });
+

We demand addedToGraph to ensure we update the display when the thermostat starts. +We also add a side effect block to update the UI.

+

Now when you click the Up and Down buttons you should see the heating display change based on desiredTemperature changes.

+

Heating Equipment

+

In a real thermostat, whenever heatOn changes, we would send a signal to real heating equipment somewhere else in the house. +Since we don’t have that available, we will simulate our own heat and demonstrate how we can mix in other asynchronous elements.

+

We’ll add a new behavior.

+
        this.sideEffect(() => {
+          document.querySelector('#heatStatus').innerText = this.heatOn.value ? "On" : "Off"
+        });
+      });
+
+    this.behavior()
+      .demands(this.heatOn)
+      .runs(() => {
+        if (this.heatOn.justUpdatedTo(true)) {
+        	// turn heat on
+        } else if (this.heatOn.justUpdatedTo(false)) {
+        	// turn heat off
+        }      
+      });
+

This new behavior responds to heatOn updates. +It uses .justUpdatedTo() to differentiate changing to true or false.

+

At this point we want to make an important point about the way state resources work. +Even though the behavior that supplies heatOn calls .update() every time it runs, it doesn’t necessarily update the state resource. +Behavior Graph uses === to check if the new value is different from the starting value. +If they are the same, the state resource does not actually update. +Therefore, demanding behaviors are not activated.

+

As an example, if heatOn.value is currently false, calling heatOn.update(true) will update the resource and activate demanding behaviors. However, if in the next event we also call heatOn.update(true), Behavior Graph will check true === true and therefore will not actually update or activate demanding behaviors.

+

Turning On

+

We can use the built-in Javascript API setInterval() to simulate our heat changing over a period of time. +When on, this timer will increment our current temperature by 1 every 1.5 seconds.

+
        if (this.heatOn.justUpdatedTo(true)) {
+          	this.sideEffect(() => {
+          		this.heatingIntervalId = setInterval(() => {
+              	this.action(() => {
+                	this.currentTemperature.update(this.currentTemperature.value + 1);
+                });
+              }, 1500);
+            });
+        } else if (this.heatOn.justUpdatedTo(false)) {
+

This branch creates a side effect which starts the timer and saves that timer directly to a normal property heatingIntervalId. +We will use this to stop the timer later. +When the timer fires, we create an action to bring new information into Behavior Graph. +In this case, the new information is that currentTemperature has increased by 1. +Note we are accessing currentTemperature.value inside a side effect block which means we don’t need to add it as a demand of the behavior.

+

heatingIntervalId is a normal Javascript property. +You are always welcome to use normal properties and methods inside behaviors however you like. +You just won’t get the additional support from Behavior Graph for those uses. +In this case, we don’t need to respond to any changes with it so we just save it to a property.

+

Turning Off

+

If you run this program now, the heat will start incrementing but it won’t stop once the heat turns off. +We will add an additional side effect for this.

+
        } else if (this.heatOn.justUpdatedTo(false)) {
+          this.sideEffect(() => {
+            clearInterval(this.heatingIntervalId);
+            this.heatingIntervalId = null;
+          });
+        }      
+
+

This side effect cancels our timer when the heat turns off. +clearInterval() is a built-in Javascript method to cancel the timer. +We set the property to null for cleanliness.

+

Now run the code and turn the desired temperature up a few degrees from the current temperature and wait. +You will see the current temperature slowly increase until they equal and the heat will turn off.

+

Behavior Graph Programming

+

This code is typical Behavior Graph programming style. +The path we went through to get here is typical of the Behavior Graph programming process. +The important step is learning how to organize code into behaviors.

+

Control Flow for Free

+

Behaviors are never called directly, which can feel like a lack of control. +This is a fair intuition, but also incorrect. +Behavior Graph improves our ability to express the intent of our code. +We do not think in terms of “do this now”. +Instead we think, “here are the reasons why this should run”.

+

Behavior Graph determines the behavior that should run next based on which behaviors have been activated and their dependencies. +A behavior that may influence another behavior will always run first.

+

Looking a the behaviors in our Thermostat program and their linked resources we can figure out exactly how things will run. +Here’s the sequence of steps when we click the Up button.

+
    +
  1. Action: up.update(), activate Behavior 1
  2. +
  3. Behavior 1: desiredTemperature.update(61), activate Behavior 2, create Side Effect 1
  4. +
  5. Behavior 2: heatOn.update(true), activate Behavior 3, create Side Effect 2
  6. +
  7. Behavior 3: create Side Effect 3
  8. +
  9. Side Effect 1: #desiredTemperature HTML element changes to “61”
  10. +
  11. Side Effect 2: #heatStatus HTML element changes to “On”
  12. +
  13. Side Effect 3: Create simulated “heating” timer
  14. +
+

The status quo approach of organizing around method calls leaves us open to potential errors as dependencies change. +With Behavior Graph, if we introduce a new dependency for Behavior 1, the rest of the control flow adapts. +Everything will continue to run in the correct order. +This is Behavior Graph doing the work for you.

+

Incremental Adoption

+

Behavior Graph is not the solution to all programming problems. +It is a tool for structuring the event driven logic portion of your software. +Feel free to use it as much or as little as you like.

+

When introducing it incrementally to an exiting codebase, it is easiest to work back from the output.

+
    +
  1. Find a place were you update the UI, start an animation, or make a network call.
  2. +
  3. Wrap that up in a side effect inside a behavior.
  4. +
  5. Then figure out what new information should cause that behavior to run.
  6. +
  7. Turn that information into resources.
  8. +
  9. Either update those resources inside action blocks or write new behaviors to supply them.
  10. +
  11. Repeat.
  12. +
+

Congratulations

+

Congratulations! You have completed the second tutorial. +You can see the finished tutorial code here.

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

3 - Tutorial 3 - Extents

+ +

In this tutorial we will create a simple todo list.

+

Todo List

+

A todo list is interesting because it has user interface elements with independent lifetimes. +When we start, our list is empty. +The visible interface elements are the header for adding new items and a footer for the remaining items. +After we click Save, a new item will appear with a checkbox for completing it, and a button for deleting it. +The list as a whole has a longer lifetime than the individual items.

+

We will implement this by adding and removing Extents from the graph as we add and remove items from our list. +This is a powerful and practical technique that gives Behavior Graph a unique expressiveness in the state management realm.

+

Initial Code

+

We have created a starter project using JSFiddle. +You should use that for this tutorial. +It has some simple HTML/CSS to represent the Todo List’s user interface. +If you wish to use your own environment you will need to copy the HTML and CSS from this JSFiddle site into your own.

+

We first want to set up the initial structure.

+
import * as bg from "https://cdn.skypack.dev/behavior-graph";
+
+class ListExtent extends bg.Extent {
+  constructor(graph) {
+    super(graph);
+
+  }
+}
+
+let graph = new bg.Graph();
+let list = new ListExtent(graph);
+list.addToGraphWithAction();
+

Adding Items

+

New code for you to add or modify will always be highlighted.

+

In order to add a new item,

+
class ListExtent extends bg.Extent {
+  constructor(graph) {
+    super(graph);
+
+    this.save = this.moment();
+    document.querySelector('#save').addEventListener('click', () => {
+      this.save.updateWithAction(document.querySelector('#new-item-text').value);
+    });
+
+    this.behavior()
+      .demands(this.save)
+      .runs(() => {
+      	// do adding here
+      });
+

We create a save moment resource to model the interaction of clicking on the Save button after typing in a new todo. +We use a normal DOM event to call save.updateWithAction() when the button it pressed.

+

Unlike in previous tutorials, with this moment resource we are passing our update method a parameter which contains the value of the text field. +Moments often carry information along with them, in this case we would like to know the textual content of the new item.

+

Next we create an empty behavior, demanding the save resource. +When save is updated, we want this behavior to create a list item and update the UI.

+

What is an Item?

+

A typical way to represent a list item is to create a data structure or object with the relevant data. +We can do something similar with a new Extent subclass.

+
  }
+}
+
+class ItemExtent extends bg.Extent {
+  constructor(graph, text, list) {
+    super(graph);
+    this.list = list;
+    this.itemText = this.state(text);
+  }
+}
+
+let graph = new bg.Graph();
+let list = new ListExtent(graph);
+list.addToGraphWithAction();
+

We add a new ItemExtent subclass and pass in some information into its constructor.

+
    +
  1. A required Graph instance
  2. +
  3. The text of the new todo list item which we store in an itemText state resource
  4. +
  5. A pointer to the parent ListExtent instance which we will use later
  6. +
+

Creating an ItemExtent

+

Back in our ListExtent, inside our behavior we can create an ItemExtent and add it to the graph.

+
    this.behavior()
+      .demands(this.save)
+      .runs(() => {
+        if (this.save.justUpdated) {
+          let item = new ItemExtent(this.graph, this.save.value, this);
+          this.addChildLifetime(item);
+          item.addToGraph();
+        }
+      });
+

We create the new item with the contents of the text field. +Then we call .addChildLifetime(item). +This lets Behavior Graph know that our ListExtent instance will always be around longer than any individual ItemExtent. +This will make it easier to connect behaviors in our ItemExtent to resources in our ListExtent. +We will see more on that later.

+

Next we call item.addToGraph(). +Adding an extent to the graph is a necessary step. +Until we do this, any behaviors or resources in that extent will not perform their expected roles.

+

Collecting the Items

+

We also need a way to keep track of these items as they are added.

+
    this.allItems = this.state([]);
+
+    this.behavior()
+      .supplies(this.allItems)
+      .demands(this.save)
+      .runs(() => {
+        if (this.save.justUpdated) {
+          let item = new ItemExtent(this.graph, this.save.value, this);
+          this.addChildLifetime(item);
+          item.addToGraph();
+          this.allItems.value.push(item);
+          this.allItems.updateForce(this.allItems.value);
+        }
+      });
+

allItems is a state resource initialized with an empty array. +We supply it because we will be updating it inside this behavior. +Whenever we create a new item we will append that ItemExtent instance to the end of that array via its .value property and the built in Array.push() method. +It is typical when working with extents that come and go to store them in a state resource or a collection inside a state resource.

+

Lastly, changing the contents of a collection is not equivalent to calling .update() on the owning resource. +We must update the resource so that demanding behaviors will be notified. +To do this we update the resource with its own contents. +We do this with .updateForce(). +We cannot just call .update() because the contents are still the same array instance. +.update() automatically filters out updates when the old value === the new value. +.updateForce() works identically but ignores this check. +This is a common pattern when storing collections inside a resource.

+

Updating the UI

+

Adding an item still doesn’t update the UI to match. +Inside our ItemExtent we add some code to create a DOM node.

+
class ItemExtent extends bg.Extent {
+  constructor(graph, text, list) {
+    super(graph);
+    this.list = list;
+    this.itemText = this.state(text);
+    this.itemElement = document.querySelector('#templates .list-item').cloneNode(true);
+  }
+}
+

This is a normal property that points to a DOM element we create by cloning some template content inside the existing HTML document. +Then inside our ListExtent behavior we can add our list item UI.

+
      .runs(() => {
+        if (this.save.justUpdated) {
+          let item = new ItemExtent(this.graph, this.save.value, this);
+          this.addChildLifetime(item);
+          item.addToGraph();
+          this.allItems.value.push(item);
+          this.allItems.updateForce(this.allItems.value);
+          this.sideEffect(() => {
+            document.querySelector('#list').appendChild(item.itemElement);
+            document.querySelector('#new-item-text').value = '';
+          });
+        }
+

This side effect adds the DOM element that our new ListExtent instance points to. +It also clears the text field so we can add additional items.

+

Try adding some items by typing in the box and clicking Save. +It seems to add items but we only see empty text. +We can fix that by using our addedToGraph built in resource.

+

Inside ItemExtent a new behavior.

+
    this.itemText = this.state(text);
+    this.itemElement = document.querySelector('#templates .list-item').cloneNode(true);
+
+    this.behavior()
+      .demands(this.itemText, this.addedToGraph)
+      .runs(() => {
+        this.sideEffect(() => {
+          this.itemElement.querySelector('.item-text').innerText = this.itemText.value;
+        });
+      });
+

This behavior will run when the ItemExtent is added to the graph updating its innerText HTML content. +We also added a demand on itemText since we would expect that to change the UI if it ever changes as well. +Now running our code and adding a few items will show our list correctly.

+

Completing Items

+

There’s a checkbox to complete a todo list item. +Checking it at this point does nothing. +Let’s fix that.

+

Inside ItemExtent

+
    this.list = list;
+    this.itemText = this.state(text);
+    this.itemElement = document.querySelector('#templates .list-item').cloneNode(true);
+    this.completed = this.state(false);
+    this.itemElement.querySelector('.completed-checkbox').addEventListener('change', () => {
+      this.completed.updateWithAction(!this.completed.value);
+    });
+

We add a new completed state resource that defaults to false. +We also add a DOM event for when the checkbox is checked so we can update completed.

+

And we add an additional behavior inside ItemExtent

+
    this.behavior()
+      .demands(this.completed, this.addedToGraph)
+      .runs(() => {
+        this.sideEffect(() => {
+          let completedClass = 'completed';
+          if (this.completed.value) {
+            this.itemElement.classList.add(completedClass);
+          } else {
+            this.itemElement.classList.remove(completedClass);
+          }
+        });
+      });
+

This behavior creates a side effect which adds a “completed” class to our HTML item. +This uses the existing CSS to strike-through a completed todo item. +We also include addedToGraph as an additional demand. +It is not strictly necessary at this point because all todo items start off as not completed. +However, it is good practice to use it in behaviors that generate side effects to reflect the current state. +If we were to introduce functionality later for saving and restoring todo lists, we may have items that start in a completed state.

+

Running this and checking/unchecking todo list items should update the UI accordingly.

+

Dynamic Behaviors

+

We will now introduce functionality that takes advantage of Behavior Graph’s ability to dynamically adjust demands and supplies.

+

Remaining Items

+

The “Remaining Items” footer of the UI does not update currently. +First we need it to respond when adding items.

+

Inside ListExtent we add a new behavior.

+
    this.behavior()
+      .demands(this.allItems, this.addedToGraph)
+      .runs(() => {
+        this.sideEffect(() => {
+          let count = this.allItems.value.filter(item => !item.completed.value).length;
+          document.querySelector('#remaining-count').textContent = count;
+        });
+      });
+

This behavior will create a side effect to update the remaining items text to match the current number of non-completed items in the list. +allItems is a demand because we want to run it whenever we add a new item to the list. +Inside the side effect we are able to iterate over the array of ItemExtent instances to check the .value of their completed state resource. +addedToGraph ensures we have the correct starting value in there since it starts out empty.

+

Now try adding a few items to the list and you will see the remaining items count increment.

+

Updating Remaining Items

+

If you try to complete an item however our remaining items count does not change. +This is because that new behavior does not demand the completed resource from our ItemExtent instances. +However, we cannot just add it inside the list of demands because the set of ItemExtent instances changes over time.

+

Behaviors have another clause for handling these situations.

+
    this.behavior()
+      .demands(this.allItems, this.added)
+      .dynamicDemands([this.allItems], () => {
+        return this.allItems.value.map(item => item.completed);
+      })
+      .runs(() => {
+        this.sideEffect(() => {
+          let count = this.allItems.value.filter(item => !item.completed.value).length;
+          document.querySelector('#remaining-count').textContent = count;
+        });
+      });
+

.dynamicDemands() is another clause when creating a behavior that lets you specify an additional list of demands that can change. +It takes two parameters. +The first is an array of resources. +Whenever any of those update, it will run the anonymous function in the second parameter. +That function returns a list of additional demands this behavior should have.

+

Here our dynamic demands clause will return an array containing the completed resource from each ItemExtent instance. +So each time we add a new item, our behavior will adapt so that it will run when the completed resource for that item updates.

+

Now try running the code. +You will see that adding new items updates the remaining items count. +And you will see that checking and unchecking the box on those items affects the remaining count as well.

+

Remaining Items Revisited

+

Its worth a little extra effort to consider what we just did. +The entire remaining items feature is defined by this single behavior.

+

Let’s compare this with a status quo implementation: methods, properties, and objects. +First we might have a method similar to our run block to update the UI

+
// Hypothetical Code -- Don't type this in
+updateRemainingCount() {
+  let count = this.allItems.filter(item => !item.completed).length;
+  document.querySelector('#remaining-count').textContent = count;
+}
+

That seems reasonable, but its not enough. +We need to go inside another method somewhere else in this same class to ensure this gets called when we add a new item. +Perhaps it might look like this:

+
// Hypothetical Code -- Don't type this in
+saveButtonPressed(text) {
+  let save = new Item(text);
+  this.allItems.push(save);
+  this.updateRemainingCount();
+}
+

Ok, so the feature is in two places. +That’s manageable. +Unfortunately, to handle completing, we still need to call in from another place in the code inside the Item class.

+
// Hypothetical Code -- Don't type this in
+completeChecked(checked) {
+  this.completed = checked;
+  this.updateRemainingCount();
+}
+

Now our feature is spread across multiple classes. +And when we add a way to remove items we will need to involve another code-path. +This type of spread out logic is a real challenge for developers. +It is incredibly easy to miss a case.

+

Production software is significantly more complex than this trivial example. +Most developers are swimming in control flows like this. +Behavior Graph lets us collect the “what” and the “why” all together in the same behavior. +The problem literally disappears.

+

Deleting Items

+

We also have a Delete button on each list item which does nothing currently. +We will fix that now.

+

Inside ItemExtent we add some button click handling.

+
    this.itemElement = document.querySelector('#templates .list-item').cloneNode(true);
+    this.completed = this.state(false);
+    this.itemElement.querySelector('.completed-checkbox').addEventListener('change', () => {
+      this.completed.updateWithAction(!this.completed.value);
+    });
+    this.itemElement.querySelector('.item-delete').addEventListener('click', () => {
+      this.list.removeItem.updateWithAction(this);
+    });
+

This takes a DOM event and updates the removeItem resource on ListExtent (which we haven’t added yet). +It is common to interact with resources on other extents and a source of conceptual power. +Here we are saying, “this list item is requesting to be removed.”

+

Note that each ItemExtent’s Delete button updates the same list.removeItem resource. +We are allowed to update resources from multiple actions because only one action will happen during a single event.

+

Now, inside ListExtent,

+
    this.allItems = this.state([]);
+    this.removeItem = this.moment();
+
+    this.behavior()
+      .supplies(this.allItems)
+      .demands(this.save, this.removeItem)
+      .runs(() => {
+        if (this.save.justUpdated) {
+          let item = new ItemExtent(this.graph, this.save.value, this);
+          this.addChildLifetime(item);
+          item.addToGraph();
+          this.allItems.value.push(item);
+          this.allItems.updateForce(this.allItems.value);
+          this.sideEffect(() => {
+            document.querySelector('#list').appendChild(item.itemElement);
+            document.querySelector('#new-item-text').value = '';
+          });
+        } else if (this.removeItem.justUpdated) {
+          let item = this.removeItem.value;
+          item.removeFromGraph();
+          this.allItems.update(this.allItems.value.filter(listItem => listItem !== item));
+          this.sideEffect(() => {
+            document.querySelector('#list').removeChild(item.itemElement);
+          });
+        }
+      });
+

These changes make up the remove item feature. +First we have a new removeItem moment resource. +removeItem models the concept of “a request to be removed happened”. +We add removeItem as an additional demand on our allItems behavior. +This causes the behavior to run when a user clicks on a Delete button.

+

It is common to refer to behaviors by the resources they supply. +This is because a behavior uniquely supplies those resources. +In this case we call this the allItems behavior.

+

We are modifying this behavior because removing an item affects the list in allItems. +We could not put this logic in another behavior because a resource can only be supplied by one behavior. +Updating a resource can only happen in the one behavior that supplies it.

+

Inside the runs block we add new checks for save.justUpdated and removeItem.justUpdated. +It is a common pattern to iterate through .justUpdated checks of the various demands to determine what happened. +In this case we remove the item from the list by building a new list without the item to remove. +So we do not need to call .forceUpdate() like we did when adding the item. +Our side effect ensures that the UI updates as well.

+

Also note that we call.removeFromGraph() on the removed ItemExtent. +Extents should always be removed from the graph if they are no longer needed otherwise their behaviors will continue to run.

+

Remaining Items Re-revisited

+

You may also notice that the remaining items count now goes down if you remove an item that hasn’t been completed yet. +We get this for free because we defined the remaining items on the allItems list. +If we were just using method calls to implement delete, we very likely would have removed the item from our list directly and then had to remember to call some updateRemainingCount() which could have easily been forgotten.

+

This ability to make chances without introducing additional complexity is a hallmark of programming with Behavior Graph. +Once you’ve experienced it a few times you will find it difficult to give up.

+

Editing

+

Now we will introduce some editing functionality. +This will cover some additional uses of dynamic behaviors. +We will allow the user to click on a particular todo list item to select it. +While selected, the user can edit the text inside the main text field.

+

Selecting

+

The first step is to use a DOM event to identify when we have selected a particular item.

+

Inside ItemExtent add another handler.

+
    this.itemElement.querySelector('.item-delete').addEventListener('click', () => {
+      this.list.removeItem.updateWithAction(this);
+    });
+    this.itemElement.querySelector('.item-text').addEventListener('click', () => {
+    	this.list.selectRequest.updateWithAction(this);
+    });
+

selectRequest updates with the list item that was clicked as its .value.

+

Inside ListExtent we add the related resources and a corresponding behavior.

+
    this.allItems = this.state([]);
+    this.removeItem = this.moment();
+    this.selectRequest = this.moment();
+    this.selected = this.state(null);
+
    this.behavior()
+      .supplies(this.selected)
+      .demands(this.selectRequest)
+      .runs(() => {
+      	this.selected.update(this.selectRequest.value);
+      });
+

Clicking on an item sets our new selected resource as the item that was just clicked.

+

Selected

+

Now we want our items to visually reflect when they are selected. +We can do this by demanding this resource in a behavior in each ItemExtent.

+
	this.behavior()
+      .demands(this.list.selected)
+      .runs(() => {
+      	let selected = this.list.selected.value === this;
+        this.sideEffect(() => {
+          let selectedClass = 'selected'
+          if (selected) {
+          	this.itemElement.classList.add(selectedClass);
+          } else {
+            this.itemElement.classList.remove(selectedClass);
+          }
+        });
+      });
+

When the selected state resource inside ListExtent updates, this behavior on every item will run. +They each demand this.list.selected. +Depending on if the item is the one that is selected we will change the UI accordingly.

+

We want to refer back to the beginning where we called .addChildLifetime(item) inside ListExtent.

+
          let item = new ItemExtent(this.graph, this.save.value, this);
+          this.addChildLifetime(item);
+          item.addToGraph();
+

This line says that the list will always be around when the item is. +This gives us permission to add this.list.selected, a resource in ListExtent, as a demand on the behavior inside each ItemExtent. +Behavior Graph ensures that we don’t link to resources that may no longer be part of the graph and it uses lifetimes as a way to manage that.

+

You can now try out this code by clicking on different items.

+

Notice that we can take a list of many items and click on different ones and watch it switch. +Each time, one of those behaviors adds the ‘selected’ CSS class while all the rest remove the ‘selected’ class. +Removing a class when its already not there is valid and simplifies our logic.

+

Deselect

+

Its easy enough to introduce deselecting by clicking on the already selected element.

+

Inside ListExtent we modify our selected behavior.

+
    this.behavior()
+      .supplies(this.selected)
+      .demands(this.selectRequest)
+      .runs(() => {
+      	if (this.selected.value == this.selectRequest.value) {
+          this.selected.update(null);
+        } else {
+        	this.selected.update(this.selectRequest.value);      
+        }
+      });
+

We check if the currently selected item is the one that was just clicked on and set it to null in that case. +This communicates that nothing should be selected. +Try running now and clicking on an item multiple times.

+

Updating The Text Field

+

Now we want to introduce editing. +Let’s try updating the main text field when we select an item so we can edit it.

+
    this.behavior()
+      .supplies(this.selected)
+      .demands(this.selectRequest)
+      .runs(() => {
+      	if (this.selected.value == this.selectRequest.value) {
+          this.selected.update(null);
+        } else {
+        	this.selected.update(this.selectRequest.value);      
+        }
+        
+        if (this.selected.justUpdated) {
+          this.sideEffect(() => {
+            let textField = document.querySelector('#new-item-text');
+            textField.value = this.selected.value === null ? '' : this.selected.value.itemText.value;
+            let actionText = document.querySelector('#action');
+            actionText.innerText = this.selected.value === null ? 'Add' : 'Edit'
+          });
+        }
+      });
+

Whenever selected updates, we run this new side effect. +It copies over the text of the item into the text field. +It also updates the UI to indicate that we are editing and not adding.

+

Conversely, when selected updates to null, it puts our UI state back to an Add mode.

+

Preventing Adding

+

When we are in editing mode, the save button should cause the text in our item to update. +However right now it will still create a new item. +We want to prevent that from happening when we are in editing mode.

+
    this.behavior()
+      .supplies(this.allItems)
+      .demands(this.save, this.removeItem)
+      .runs(() => {
+        if (this.save.justUpdated && this.selected.traceValue === null) {
+          let item = new ItemExtent(this.graph, this.save.value, this);
+          this.addChildLifetime(item);
+          item.addToGraph();
+          this.allItems.value.push(item);
+

At the time we click the Save button, we want to know if we are in editing mode or not. +We could check selected.value to see if it is null (ie not editing). +However, here we use selected.traceValue instead. +.traceValue is the value of the resource at the beginning of the graph event (the instant the action started). +So if selected updates this event, .traceValue will still return what it was before it changed.

+

This also removes the requirement that we demand selected in this behavior. +Here we just care if an item is already selected or not, not that something was “just selected”. +So we don’t need it as a demand. +.traceValue of any resource is always accessible by any behavior without demanding (or supplying) it.

+

The if check ignores the save click when there’s something already selected.

+

Making Changes

+

Now we can add a new behavior inside ListExtent that responds to our save and updates the text of the selected item.

+
        }
+      });
+      
+    this.behavior()
+      .dynamicSupplies([this.allItems], () => {
+        return this.allItems.value.map(item => item.itemText);
+      })
+      .demands(this.save)
+      .runs(() => {
+      	if (this.save.justUpdated && this.selected.traceValue !== null) {
+          this.selected.traceValue.itemText.update(this.save.value);
+        }
+      });
+      
+    this.behavior()
+      .demands(this.allItems, this.addedToGraph)
+

This new behavior uses .dyanmicSupplies(). +This is a clause we haven’t seen before. +It does work similarly to .dynamicDemands(). +In this behavior, we update our supplies to be the itemText resource from each ItemExtent instance. +Whenever we add our remove an item, this behavior will update its supplies.

+

We will supply all of them because any one of them might become selected. +When the user clicks the Save button, this behavior will update the itemText on the selected item to whats inside the text field.

+

Notice that we use selected.traceValue again here, so it is not part of the demands. +We want which item was selected at the time save was updated. +We also do not need this behavior to run when selected updates.

+

Notice that all we do is update itemText. +We already have a behavior that knows how to change that UI when we change the text. +It is common to make these kinds of changes and see everything work as expected.

+

Run the code and you will see your working todo list.

+

Challenge

+

After saving our changes, the item remains selected. +It might be a better user experience to exit editing mode after saving. +Can you implement this?

+

Try your best before looking at the answer.

+

Hints:

+
    +
  1. You can do this by modifying a single behavior.
  2. +
  3. Which behavior is responsible for selected?
  4. +
  5. Which resource updates when we click the Save button?
  6. +
+

Answer: Clearing Post Save

+

We can modify our selected behavior inside ListExtent.

+
    this.behavior()
+      .supplies(this.selected)
+      .demands(this.selectRequest, this.save)
+      .runs(() => {
+      	if (this.selectRequest.justUpdated) {
+      	  if (this.selected.value == this.selectRequest.value) {
+            this.selected.update(null);
+          } else {
+          	this.selected.update(this.selectRequest.value);      
+          }        
+        } else if (this.save.justUpdated) {
+          this.selected.update(null);
+        }
+

Now our selected behavior also runs and deselects the current item when the Save button is pressed. +Here see again the common pattern of checking various resources' .justUpdated property inside a behavior.

+

Just before adding this feature we used selected.traceValue in a few behaviors. +This change here is an additional motivation for that. +If we used selected.value in those behaviors it means they would demand selected which is supplied by this behavior. +Which means they would run after this behavior. +Which means by they time they ran, selected.value would be null. +We don’t want what selected changes to, we want what it was at the start. +This is what traceValue provides.

+

Congratulations

+

Congratulations! You have completed the third tutorial. +You can see the finished tutorial code here.

+ +
+ + + + + + + + + +
+
+
+ +
+
+
+
+ +
+
+ +
+
+ © 2022 Yahoo All Rights Reserved + + + + +
+
+
+
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/typescript/tutorials/index.html b/docs/typescript/tutorials/index.html new file mode 100644 index 0000000..35deb39 --- /dev/null +++ b/docs/typescript/tutorials/index.html @@ -0,0 +1,290 @@ + + + + + + + + + + + + + + + + + + + + + + +Tutorials | Behavior Graph + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+
+
+
+ + +
+ + + + + +
+

Tutorials

+ + + +
+ + + + + + + + +
+ + +
+
+ Tutorial 1 - Basics +
+

+
+ + +
+
+ Tutorial 2 - IO +
+

+
+ + +
+
+ Tutorial 3 - Extents +
+

+
+ + +
+ + + + +
+ +
+
+
+ +
+
+
+
+ +
+
+ +
+
+ © 2022 Yahoo All Rights Reserved + + + + +
+
+
+
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/typescript/tutorials/index.xml b/docs/typescript/tutorials/index.xml new file mode 100644 index 0000000..b57ef55 --- /dev/null +++ b/docs/typescript/tutorials/index.xml @@ -0,0 +1,17 @@ + + + Behavior Graph – Tutorials + https://yahoo.github.io/bgdocs/docs/typescript/tutorials/ + Recent content in Tutorials on Behavior Graph + Hugo -- gohugo.io + + + + + + + + + + + diff --git a/docs/typescript/tutorials/tutorial-1/index.html b/docs/typescript/tutorials/tutorial-1/index.html new file mode 100644 index 0000000..9c6a00d --- /dev/null +++ b/docs/typescript/tutorials/tutorial-1/index.html @@ -0,0 +1,708 @@ + + + + + + + + + + + + + + + + + + + + +Tutorial 1 - Basics | Behavior Graph + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+
+
+
+ + +
+ + + + + +
+

Tutorial 1 - Basics

+ + +

Here we will introduce the essentials to get you started quickly using Behavior Graph.

+

The recommended way to get started is to use our preconfigured tutorial site.

+

If you prefer to set up your own environment please see the Quick Start page. +Make sure to open up the Javascript console. +That is where we will generate our output.

+

Hello, World!

+

Type in the following into the editor. +You will gain more by typing it, as it forces you to think about each line.

+
import * as bg from "https://cdn.skypack.dev/behavior-graph";
+
+let g = new bg.Graph();
+
+class HelloExtent extends bg.Extent {
+  constructor(graph) {
+    super(graph);
+    
+    this.person = this.state("Nobody");
+    this.behavior()
+      .demands(this.person)
+      .runs(() => {
+        console.log("Hello, " + this.person.value + "!");
+      });
+  }
+}
+
+let e = new HelloExtent(g);
+
+e.addToGraphWithAction();
+
+g.action(() => {
+  e.person.update("World");
+});
+

Run the code. +In the console you should see

+
"Hello, World!"
+

The Parts

+

Let’s review this in pieces.

+
import * as bg from "https://cdn.skypack.dev/behavior-graph";
+

This is a standard Javascript import. +You may need to adjust it depending on your Javascript environment which is beyond the scope of this tutorial. +Behavior Graph is distributed though NPM and is available through a number of downstream CDNs. +See the Quick Start page for more information. +Note that Behavior Graph is imported as bg here. +We will reference that in a few places in the tutorial. +Your import name may be different.

+
let g = new bg.Graph();
+

You must create an instance of a Graph. +You may have more than one instance, but all Behavior Graph elements are associated with a specific instance.

+
class HelloExtent extends bg.Extent {
+  constructor(graph) {
+    super(graph);
+

You will modularize your Behavior Graph code into Extents. +You do this by extending the built in Extent class and passing it your Graph instance in the constructor. +Extents collect Behaviors and Resources together with the same lifetime.

+
    this.person = this.state("Nobody");
+

person is a Resource. +Resources are containers for information. +This specifically is a State resource. +State resources contain persistent information, i.e. it may be used in the future. +You will define state resources as properties on your Extent subclass and create them with the .state() factory method. +State resources always have an initial value. +Our person resource has an initial value of "Nobody".

+
    this.behavior()
+      .demands(this.person)
+      .runs(() => {
+        console.log("Hello, " + this.person.value + "!");
+      });
+

This is a Behavior. +Behaviors are units of functionality. +We create them with the .behavior() factory method that uses a fluent BehaviorBuilder API.

+

This behavior has two parts. +The .demands() clause states that this behavior depends on the resource person.

+

The .runs() clause is the code that gets run whenever one (or more) of the demands is updated (has new information). +This one prints our greeting using this.person.value. +The .value property returns the contents of our person state resource. +A behavior must demand a resource in order to access its .value property. +(It can also access it if it supplies the resource as well.)

+
let e = new HelloExtent(g);
+e.addToGraphWithAction();
+

We will need to create an instance of our HelloExtent in order to add it to the graph. +Then we call .addToGraphWithAction() which adds the HelloExtent’s resource and behavior to our graph. +They will not perform any work until their extent has been added.

+
g.action(() => {
+  e.person.update("World");
+});
+

Here we create a new Action using .action() on our Graph instance. +Action blocks are how we introduce new information from the outside. +In this case, we are providing the person’s name by calling .update() on our person state resource.

+

How it works

+

This call to .action() will start a series of steps.

+
    +
  1. It will run the anonymous function given as a parameter.
  2. +
  3. e.person.update() will tell the graph to mark any demanding behaviors as activated. +In this case there is the only one demanding behavior.
  4. +
  5. The anonymous function will complete.
  6. +
  7. The graph will call the runs block on the one activated behavior.
  8. +
  9. That runs block prints out “Hello, World!” by accessing the .value of person which is the value we passed into the .update() method.
  10. +
  11. The .action() method completes and the program continues.
  12. +
+

All of these steps together make up a single Behavior Graph Event.

+

Doing More

+

While this may seem like a tedious implementation of “Hello, World”, we have already established a foundation that will let this program grow to arbitrary complexity. +The computer can use these components to support us throughout the development process.

+

Let’s introduce a second reason why we may need to print our greeting.

+

The highlighted lines will always be the new or updated lines

+
    this.person = this.state("Nobody");
+    this.greeting = this.state("Greetings");
+    this.behavior()
+      .demands(this.person, this.greeting)
+      .runs(() => {
+        console.log(this.greeting.value + ", " + this.person.value + "!");
+      });
+

First we create a second state resource, greeting. +Then we add greeting as an additional demand. +We must add it as a demand because we access its .value property. +Behavior Graph will raise an error if we do not. +This explicitness is by design. +Finally we modify our message to use greeting.value.

+

When we run our program now it should produce

+
"Greetings, World!"
+

If we want to get back to our original message we can add more to our action.

+
g.action(() => {
+  e.person.update("World");
+  e.greeting.update("Hello");
+});
+

Now we have

+
"Hello, World!"
+

Multiple Updates

+

This illustrates an important distinction between Behavior Graph and many reactive libraries. +Our behavior demands multiple resources. +That means whenever either person or greeting or both update our behavior should run. +However it doesn’t run immediately, it is only activated.

+

Inside our action we update both person and greeting. +Our behavior that demands them will not run until the entire action block has completed. +All updates inside a single action are treated as if they happened at the same time. +This means our behavior runs only once.

+

We aren’t required to provide both just because we demand both. +State resources persist their value from action to action. +Let’s add an additional action to see this.

+
g.action(() => {
+  e.person.update("World");
+  e.greeting.update("Hello");
+});
+g.action(() => {
+  e.greeting.update("Goodbye");
+});
+

Now in our console it should print

+
"Hello, World!"
+"Goodbye, World!"
+

“World” persisted into the second event. While “Goodbye” replaced the previous greeting.

+

Moments

+

Not all information persists. +Sometimes things just happen. +A button press is a typical example. +We can model this information with Moment resources.

+
    this.person = this.state("Nobody");
+    this.greeting = this.state("Greetings");
+    this.button = this.moment();
+    this.behavior()
+      .demands(this.person, this.greeting, this.button)
+      .runs(() => {
+        if (this.button.justUpdated) {
+          console.log(this.greeting.value + ", " + this.person.value + "!");
+        }
+      });
+

First we create a button resource. +We create it with a .moment() factory method on our Extent subclass. +Then we add it to our behavior’s list of demands so it runs when button updates.

+

Inside our runs block, we’ve gated our log statement by checking against button.justUpdated. +This will be true only if some other part of our code called button.update() during the same event.

+

Press the Button

+

If you run the program now you will get no output. +This is because we only update the person and greeting resources and our log statement only runs when button.justUpdated is true.

+

So lets add some additional lines to simulate a button press.

+
g.action(() => {
+  e.person.update("World");
+  e.greeting.update("Hello");
+});
+g.action(() => {
+  e.greeting.update("Goodbye");
+});
+g.action(() => {
+  e.button.update();
+});
+

Now our program outputs:

+
"Goodbye, World!"
+

The first two actions only update the state resources. +Our behavior is run but the if (this.button.justUpdated) check prevents anything from happening. +The third action causes the behavior to run as well. +This time the if check passes and it logs the message based on prior updates.

+

Of course they don’t need to be in separate actions.

+
g.action(() => {
+  e.button.update();
+  e.greeting.update("Nevermind");
+});
+

Will output:

+
"Nevermind, World!"
+

The message changed because both button updated as well as greeting in that same action. +The order in which they were updated inside the action is irrelevant to any demanding behaviors.

+

A Graph

+

With only one behavior, it is difficult to call it a behavior graph. +The real power of Behavior Graph comes with the ability to incrementally introduce related functionality. +Behaviors will often depend on information provided by other behaviors.

+

Supplies

+

Imagine, for security sake, that we would like to introduce logging into our “Hello, World” program.

+
    this.button = this.moment();
+    this.message = this.state(null);
+    this.behavior()
+      .supplies(this.message)
+      .demands(this.person, this.greeting, this.button)
+      .runs(() => {
+        this.message.update(this.greeting.value + ", " + this.person.value + "!");
+        if (this.button.justUpdated) {
+          console.log(this.message.value);
+        }
+      });
+

We add a new state resource, message, to save the current message. +We add this resource to a new supplies clause of our behavior definition with .supplies(). +Supplies are resources that this behavior is solely responsible for. +It means that a behavior can both read a resource’s .value and .update() it as well.

+

We call message.update() with the text contents of the greeting to save them for later.

+ + + + +

Logging Behavior

+

We can introduce the logging functionality by adding an additional behavior.

+
        if (this.button.justUpdated) {
+          console.log(this.message.value);
+        }
+      });
+      
+    this.behavior()
+      .demands(this.message)
+      .runs(() => {
+        console.log("Message changed to: " + this.message.value);
+      });
+

This new behavior demands message. +This means it will run whenever message updates. +Our output shows this result:

+
"Message changed to: Hello, World!"
+"Message changed to: Goodbye, World!"
+"Nevermind, World!"
+"Message changed to: Nevermind, World!"
+

As you can see our new logging behavior runs and generates output each time the message changes.

+

Events

+

In Behavior Graph we call a single pass through the graph (from the start of an action to the last output) an Event. +Our current output is the result of three events.

+

First Event:

+
graph LR
+  a["Action:<br />person=>World<br />greeting=>Hello"] --> b["Behavior 1:<br />message=>Hello, World!"] --> c["Behavior 2:<br />message change logged"]
+

Second Event:

+
graph LR
+  a["Action:<br />greeting=>Goodbye"] --> b["Behavior 1:<br />message=>Goodbye, World!"] --> c["Behavior 2:<br />message change logged"]
+

Third Event:

+
graph LR
+  a["Action:<br />button updates<br />greeting=>Nevermind"] --> b["Behavior 1:<br />message=>Nevermind, World!<br />message printed"] --> c["Behavior 2:<br />message change logged"]
+

The Same Event

+

Every time a resource is updated, it is assigned the current event. +So in the First Event example above, when person and greeting update, they get pointers to that same event in their .event property. +Then when message updates in the first behavior it also gets a pointer to this same event.

+

We can access this event inside any behavior that we demand (or supply). +This can use this to append a timestamp to our log messages.

+
    this.behavior()
+      .demands(this.message)
+      .runs(() => {
+        console.log("Message changed to: " + this.message.value + " : " + this.message.event.timestamp);
+      });
+

You should now see something similar to the lines below

+
"Message changed to: Hello, World! : Fri Jan 28 2022 16:43:43 GMT-0800"
+"Message changed to: Goodbye, World! : Fri Jan 28 2022 16:43:43 GMT-0800"
+"Nevermind, World!"
+"Message changed to: Nevermind, World! : Fri Jan 28 2022 16:43:43 GMT-0800"
+

What Just Happened?

+

Using .justUpdated is a powerful tool for organizing our code into related functionality. +We will add additional logging to see how this works. +First we will track when we send the message.

+
    this.message = this.state(null);
+    this.sentMessage = this.moment();
+    this.behavior()
+      .supplies(this.message, this.sentMessage)
+      .demands(this.person, this.greeting, this.button)
+      .runs(() => {
+        this.message.update(this.greeting.value + ", " + this.person.value + "!");
+        if (this.button.justUpdated) {
+          console.log(this.message.value);
+          this.sentMessage.update();
+        }
+      });
+

We create a moment resource for sentMessage. +Sending the message is a one off action, so we keep track of that with a moment. +We will be calling .update() on sentMessage so we need to add it to the list of supplies. +We call this.sentMessage.update() right after the console.log call to track when we actually print out our message.

+

Note that a behavior can supply more than one resource. +This is a common pattern that lets us group related logic together without having to jump through hoops to avoid duplication.

+

Next we modify our logging message to demand this additional resource.

+
    this.behavior()
+      .demands(this.message, this.sentMessage)
+      .runs(() => {
+        if (this.message.justUpdated) {
+          console.log("Message changed to: " + this.message.value + " : " + this.message.event.timestamp);      
+        }
+        if (this.sentMessage.justUpdated) {
+          console.log("Message sent: " + this.message.value + " : " + this.message.event.timestamp);
+        }
+      });
+

This behavior now demands sentMessage which means it will run whenever that resource is updated. +Inside our run block we check to see which resource was updated and generate the correct log message. +It may be the case that either one or both is updated.

+

You will find yourself using this “what just happened?” pattern in many of your behaviors.

+

Running your program should looks like this:

+
"Message changed to: Hello, World! : Sat Jan 29 2022 08:33:05 GMT-0800"
+"Message changed to: Goodbye, World! : Sat Jan 29 2022 08:33:05 GMT-0800"
+"Nevermind, World!"
+"Message changed to: Nevermind, World! : Sat Jan 29 2022 08:33:05 GMT-0800"
+"Message sent: Nevermind, World! : Sat Jan 29 2022 08:33:05 GMT-0800"
+

Challenge

+

Can you introduce a single resource that turns on or off our newly added logging? +Try to do this challenge before looking at the answer.

+

Here’s some hints:

+
    +
  • Try adding a state resource.
  • +
  • You’ll need to demand it in a behavior and introduce some additional logic.
  • +
+

Answer

+
    this.sentMessage = this.moment();
+    this.loggingEnabled = this.state(true);
+    this.behavior()
+      .supplies(this.message, this.sentMessage)
+      .demands(this.person, this.greeting, this.button)
+      .runs(() => {
+        this.message.update(this.greeting.value + ", " + this.person.value + "!");
+        if (this.button.justUpdated) {
+          console.log(this.message.value);
+          this.sentMessage.update();
+        }
+      });
+      
+    this.behavior()
+      .demands(this.message, this.sentMessage, this.loggingEnabled)
+      .runs(() => {
+        if (this.loggingEnabled.value) {
+          if (this.message.justUpdated) {
+            console.log("Message changed to: " + this.message.value + " : " + this.message.event.timestamp);      
+          }
+          if (this.sentMessage.justUpdated) {
+            console.log("Message sent: " + this.message.value + " : " + this.message.event.timestamp);
+          }
+        }
+      });
+

loggingEnabled is our new resource. +We want it to persist so we use a state resource. +It defaults to true meaning logging is on.

+

We then need to demand it inside our logging behavior in order to access its .value property. +If we try to access .value without demanding it, Behavior Graph will raise an error.

+

We can modify our last action to see it work.

+
g.action(() => {
+  e.button.update();
+  e.greeting.update("Nevermind");
+  e.loggingEnabled.update(false);
+});
+

After adding this additional line, running our code looks like this.

+
"Message changed to: Hello, World! : Sat Jan 29 2022 08:39:43 GMT-0800"
+"Message changed to: Goodbye, World! : Sat Jan 29 2022 08:39:43 GMT-0800"
+"Nevermind, World!"
+

We no longer log the last two messages because logging was turned off in the same action. +Notice how even though loggingEnabled.update(false) comes after our updates, we still disable logging for the same event. +If you were to do this without Behavior Graph, using status quo method calls and property updates, you would need to ensure that loggingEnabled changes to false before the other updates. +It would be a different result if you updated it after. +The ability to remove the hidden complexity that comes with sequencing is a programming superpower. +Behavior Graph gives you this feature for free.

+

Ordering Resources

+

You may notice that although .loggingEnabled is a demand, we don’t actually need it to to be a reason for our logging behavior to run. +We only need to check its .value. +Behavior Graph lets us lighten this constraint.

+
    this.behavior()
+      .demands(this.message, this.sentMessage, this.loggingEnabled.order)
+      .runs(() => {
+        if (this.loggingEnabled.value) {
+          if (this.message.justUpdated) {
+

We can add .order to any resource inside our demands clause. +When we do this, updating that resource will not activate this behavior. +This can give us some additional accuracy when specifying how our behaviors are linked.

+

Complete

+

Congratulations! You have completed this first tutorial. +You can see the finished tutorial code here.

+

While you may feel that there were many new concepts introduced, we have already covered the majority of them. +You will find they come naturally with some practice. +The remaining tutorials give you a taste for how Behavior Graph works inside real interactive programs.

+ + + + +
+ + +
+
+
+ +
+
+
+
+ +
+
+ +
+
+ © 2022 Yahoo All Rights Reserved + + + + +
+
+
+
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/typescript/tutorials/tutorial-2/index.html b/docs/typescript/tutorials/tutorial-2/index.html new file mode 100644 index 0000000..39d98fa --- /dev/null +++ b/docs/typescript/tutorials/tutorial-2/index.html @@ -0,0 +1,620 @@ + + + + + + + + + + + + + + + + + + + + +Tutorial 2 - IO | Behavior Graph + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+
+
+
+ + +
+ + + + + +
+

Tutorial 2 - IO

+ + +

This tutorial will show how Behavior Graph interacts with real inputs and outputs to produce a working application. +In this case we will build the control system for a thermostat, the device in your house that controls the heat.

+

Thermostat

+

This simplified thermostat has two buttons, Up and Down for raising and lowering the desired temperature. +It also periodically gets external updates of the current temperature. +If the desired temperature is above the current temperature, we will turn on the heat. +And once they are the same, the heat will turn off.

+

Initial Code

+

We have created a starter project using JSFiddle. +You should use that for this tutorial. +It has some simple HTML/CSS to represent the Thermostat’s user interface. +If you wish to use your own environment you will need to copy the HTML and CSS from this JSFiddle site into your own.

+

The initial setup code has been provided for you.

+
import * as bg from "https://cdn.skypack.dev/behavior-graph";
+
+class Thermostat extends bg.Extent {
+  constructor(graph) {
+    super(graph);
+  }
+}
+
+let graph = new bg.Graph();
+let tm = new Thermostat(graph);
+tm.addToGraphWithAction();
+

The bulk of our application will exist inside our Thermostat subclass of Extent.

+

Desired Temperature

+

The first part of our logic will focus on setting the desired temperature. +The related elements look something like this.

+

Desired Temperature

+

First we need a state resource to track our desired temperature and a behavior to supply it.

+
class Thermostat extends bg.Extent {
+  constructor(graph) {
+    super(graph);
+
+    this.desiredTemperature = this.state(60);
+    this.behavior()
+      .supplies(this.desiredTemperature)
+      .runs(() => {
+      	// desired temperature logic will go here
+      });
+  }
+}
+

desiredTemperature is a state resource with an initial value of 60. +We want a state resource because it is information we intend to use in the future. +Our new behavior supplies this resource because we plan on calling desiredTemperature.update() inside the runs block.

+

Button Presses

+

Our thermostat will need to respond to the button press events that come from our HTML buttons.

+
    super(graph);
+
+    this.up = this.moment();
+    document.querySelector('#up').addEventListener('click', () => {
+      this.up.updateWithAction();
+    });
+
+    this.desiredTemperature = this.state(60);
+

We create an up moment resource to track when the Up button is pressed. +Then we use standard DOM manipulation code to respond to the HTML click event. +We call this.up.updateWithAction() to track this event in our moment resource.

+

.updateWithAction() is syntactic sugar for creating a new action and calling .update(). +It is the same as if we typed this instead:

+
    document.querySelector('#up').addEventListener('click', () => {
+      this.graph.action(() => {
+        this.up.update();
+      });
+    });
+

Responding to the Button

+

We need to modify our behavior to respond to this update.

+
    this.desiredTemperature = this.state(60);
+    this.behavior()
+      .supplies(this.desiredTemperature)
+      .demands(this.up)
+      .runs(() => {
+        if (this.up.justUpdated) {
+          this.desiredTemperature.update(this.desiredTemperature.value + 1);
+        }
+      });
+

We add up to our list of demands. +This ensures that this behavior activates whenever up is updated. +Inside the run block we check for .justUpdated. +If so, we update the desiredTemperature by incrementing it from its previous .value.

+ + + + +

These rules are essential to allowing Behavior Graph to ensure your resources are always in a consistent state.

+

Output

+

At this point our desiredTemperature changes when you press the Up button. +But we don’t update the display. +We add that here.

+
    this.behavior()
+      .supplies(this.desiredTemperature)
+      .demands(this.up)
+      .runs(() => {
+        if (this.up.justUpdated) {
+          this.desiredTemperature.update(this.desiredTemperature.value + 1);
+        }
+        this.sideEffect(() => {
+          document.querySelector('#desiredTemperature').innerText = this.desiredTemperature.value;
+        });
+      });
+

This behavior creates a Side Effect block. +Inside that block we use standard DOM methods to update the temperature. +Now if you run this and click on the Up button you will see the temperature field appear and increment.

+

Side effects are the correct way to generate output from inside a behavior. +Although a side effect is created inside a behavior, it will only run after all other behaviors have completed running. +This ensures that all our internal state has settled before calling code that may potentially access it.

+

Side effects do not have a restriction on what resources they can access, unlike the behavior in which they are defined.

+

Down

+

We can add the handling for our Down button in a similar way.

+
    this.up = this.moment();
+    document.querySelector('#up').addEventListener('click', () => {
+      this.up.updateWithAction();
+    });
+
+    this.down = this.moment();
+    document.querySelector('#down').addEventListener('click', () => {
+      this.down.updateWithAction();
+    });
+

And modify our behavior to respond.

+
    this.behavior()
+      .supplies(this.desiredTemperature)
+      .demands(this.up, this.down)
+      .runs(() => {
+        if (this.up.justUpdated) {
+          this.desiredTemperature.update(this.desiredTemperature.value + 1);
+        } else if (this.down.justUpdated) {
+          this.desiredTemperature.update(this.desiredTemperature.value - 1);        
+        }
+        this.sideEffect(() => {
+

Run the program. +Clicking on the Up and Down buttons should now move the desired temperature display up and down.

+

AddedToGraph

+

You may have noticed that the desired temperature display doesn’t show up until after we’ve tapped on one of the buttons. +This is because our behavior only runs when one of its demands is updated. +What we would like to do is also run it once at the beginning.

+
    this.behavior()
+      .supplies(this.desiredTemperature)
+      .demands(this.up, this.down, this.addedToGraph)
+      .runs(() => {
+        if (this.up.justUpdated) {
+

We add the this.addedToGraph resource to our list of demands. +Now when you run the code you will see that the temperature appears at the beginning.

+

addedToGraph is a built in state resource that is part of every Extent. +It is updated to true when the Extent is added to the graph. +Just like other resources you can demand it to get a behavior to run at the beginning. +And you can check it’s .justUpdated property to specialize your logic when necessary.

+

Heat

+

Now we need to introduce a separate bit of functionality to control the heating equipment. +This logic compares the current temperature to the desired temperature and turns on or off the heating equipment accordingly.

+

Current Temperature

+

Current Temperature

+

First we need a resource to track the current temperature,

+
    this.desiredTemperature = this.state(60);
+    this.currentTemperature = this.state(60);
+

and a new behavior to update the UI when that resource updates.

+
        this.sideEffect(() => {
+          document.querySelector('#desiredTemperature').innerText = this.desiredTemperature.value;
+        });
+      });
+      
+    this.behavior()
+      .demands(this.currentTemperature, this.addedToGraph)
+      .runs(() => {
+        this.sideEffect(() => {
+          document.querySelector('#currentTemperatureDisplay').innerText = this.currentTemperature.value;
+        });
+      });
+

Like with desiredTemperature this behavior runs whenever currentTemperature updates as well as once at the beginning. +It uses a side effect to update our UI.

+

Heat On

+

Next we need a resource to track if the heat is on or not.

+
    this.desiredTemperature = this.state(60);
+    this.currentTemperature = this.state(60);
+    this.heatOn = this.state(false);
+

By default the heatOn state resource is false indicating that it is off.

+
      .runs(() => {
+        this.sideEffect(() => {
+          document.querySelector('#currentTemperatureDisplay').innerText = this.currentTemperature.value;
+        });
+      });
+
+    this.behavior()
+      .supplies(this.heatOn)
+      .demands(this.currentTemperature, this.desiredTemperature)
+      .runs(() => {
+        let heatOn = this.desiredTemperature.value > this.currentTemperature.value;
+        this.heatOn.update(heatOn);
+      });
+

Here we add another new behavior. +It is responsible for updating heatOn so we add it as a supply. +It uses both currentTemperature and desiredTemperature for its logic, so both are demands. +When it runs, it updates heatOn to true if our currentTemperature is too low.

+

Heat Display

+

We want our display to update alongside the heatOn. +So we add that logic to our new behavior.

+
    this.behavior()
+      .supplies(this.heatOn)
+      .demands(this.currentTemperature, this.desiredTemperature, this.addedToGraph)
+      .runs(() => {
+        let heatOn = this.desiredTemperature.value > this.currentTemperature.value;
+        this.heatOn.update(heatOn);
+        this.sideEffect(() => {
+          document.querySelector('#heatStatus').innerText = this.heatOn.value ? "On" : "Off"
+        });
+      });
+

We demand addedToGraph to ensure we update the display when the thermostat starts. +We also add a side effect block to update the UI.

+

Now when you click the Up and Down buttons you should see the heating display change based on desiredTemperature changes.

+

Heating Equipment

+

In a real thermostat, whenever heatOn changes, we would send a signal to real heating equipment somewhere else in the house. +Since we don’t have that available, we will simulate our own heat and demonstrate how we can mix in other asynchronous elements.

+

We’ll add a new behavior.

+
        this.sideEffect(() => {
+          document.querySelector('#heatStatus').innerText = this.heatOn.value ? "On" : "Off"
+        });
+      });
+
+    this.behavior()
+      .demands(this.heatOn)
+      .runs(() => {
+        if (this.heatOn.justUpdatedTo(true)) {
+        	// turn heat on
+        } else if (this.heatOn.justUpdatedTo(false)) {
+        	// turn heat off
+        }      
+      });
+

This new behavior responds to heatOn updates. +It uses .justUpdatedTo() to differentiate changing to true or false.

+

At this point we want to make an important point about the way state resources work. +Even though the behavior that supplies heatOn calls .update() every time it runs, it doesn’t necessarily update the state resource. +Behavior Graph uses === to check if the new value is different from the starting value. +If they are the same, the state resource does not actually update. +Therefore, demanding behaviors are not activated.

+

As an example, if heatOn.value is currently false, calling heatOn.update(true) will update the resource and activate demanding behaviors. However, if in the next event we also call heatOn.update(true), Behavior Graph will check true === true and therefore will not actually update or activate demanding behaviors.

+

Turning On

+

We can use the built-in Javascript API setInterval() to simulate our heat changing over a period of time. +When on, this timer will increment our current temperature by 1 every 1.5 seconds.

+
        if (this.heatOn.justUpdatedTo(true)) {
+          	this.sideEffect(() => {
+          		this.heatingIntervalId = setInterval(() => {
+              	this.action(() => {
+                	this.currentTemperature.update(this.currentTemperature.value + 1);
+                });
+              }, 1500);
+            });
+        } else if (this.heatOn.justUpdatedTo(false)) {
+

This branch creates a side effect which starts the timer and saves that timer directly to a normal property heatingIntervalId. +We will use this to stop the timer later. +When the timer fires, we create an action to bring new information into Behavior Graph. +In this case, the new information is that currentTemperature has increased by 1. +Note we are accessing currentTemperature.value inside a side effect block which means we don’t need to add it as a demand of the behavior.

+

heatingIntervalId is a normal Javascript property. +You are always welcome to use normal properties and methods inside behaviors however you like. +You just won’t get the additional support from Behavior Graph for those uses. +In this case, we don’t need to respond to any changes with it so we just save it to a property.

+

Turning Off

+

If you run this program now, the heat will start incrementing but it won’t stop once the heat turns off. +We will add an additional side effect for this.

+
        } else if (this.heatOn.justUpdatedTo(false)) {
+          this.sideEffect(() => {
+            clearInterval(this.heatingIntervalId);
+            this.heatingIntervalId = null;
+          });
+        }      
+
+

This side effect cancels our timer when the heat turns off. +clearInterval() is a built-in Javascript method to cancel the timer. +We set the property to null for cleanliness.

+

Now run the code and turn the desired temperature up a few degrees from the current temperature and wait. +You will see the current temperature slowly increase until they equal and the heat will turn off.

+

Behavior Graph Programming

+

This code is typical Behavior Graph programming style. +The path we went through to get here is typical of the Behavior Graph programming process. +The important step is learning how to organize code into behaviors.

+

Control Flow for Free

+

Behaviors are never called directly, which can feel like a lack of control. +This is a fair intuition, but also incorrect. +Behavior Graph improves our ability to express the intent of our code. +We do not think in terms of “do this now”. +Instead we think, “here are the reasons why this should run”.

+

Behavior Graph determines the behavior that should run next based on which behaviors have been activated and their dependencies. +A behavior that may influence another behavior will always run first.

+

Looking a the behaviors in our Thermostat program and their linked resources we can figure out exactly how things will run. +Here’s the sequence of steps when we click the Up button.

+
    +
  1. Action: up.update(), activate Behavior 1
  2. +
  3. Behavior 1: desiredTemperature.update(61), activate Behavior 2, create Side Effect 1
  4. +
  5. Behavior 2: heatOn.update(true), activate Behavior 3, create Side Effect 2
  6. +
  7. Behavior 3: create Side Effect 3
  8. +
  9. Side Effect 1: #desiredTemperature HTML element changes to “61”
  10. +
  11. Side Effect 2: #heatStatus HTML element changes to “On”
  12. +
  13. Side Effect 3: Create simulated “heating” timer
  14. +
+

The status quo approach of organizing around method calls leaves us open to potential errors as dependencies change. +With Behavior Graph, if we introduce a new dependency for Behavior 1, the rest of the control flow adapts. +Everything will continue to run in the correct order. +This is Behavior Graph doing the work for you.

+

Incremental Adoption

+

Behavior Graph is not the solution to all programming problems. +It is a tool for structuring the event driven logic portion of your software. +Feel free to use it as much or as little as you like.

+

When introducing it incrementally to an exiting codebase, it is easiest to work back from the output.

+
    +
  1. Find a place were you update the UI, start an animation, or make a network call.
  2. +
  3. Wrap that up in a side effect inside a behavior.
  4. +
  5. Then figure out what new information should cause that behavior to run.
  6. +
  7. Turn that information into resources.
  8. +
  9. Either update those resources inside action blocks or write new behaviors to supply them.
  10. +
  11. Repeat.
  12. +
+

Congratulations

+

Congratulations! You have completed the second tutorial. +You can see the finished tutorial code here.

+ + + + +
+ + +
+
+
+ +
+
+
+
+ +
+
+ +
+
+ © 2022 Yahoo All Rights Reserved + + + + +
+
+
+
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/typescript/tutorials/tutorial-3/index.html b/docs/typescript/tutorials/tutorial-3/index.html new file mode 100644 index 0000000..5278e9c --- /dev/null +++ b/docs/typescript/tutorials/tutorial-3/index.html @@ -0,0 +1,845 @@ + + + + + + + + + + + + + + + + + + + + +Tutorial 3 - Extents | Behavior Graph + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+
+
+
+ + +
+ + + + + +
+

Tutorial 3 - Extents

+ + +

In this tutorial we will create a simple todo list.

+

Todo List

+

A todo list is interesting because it has user interface elements with independent lifetimes. +When we start, our list is empty. +The visible interface elements are the header for adding new items and a footer for the remaining items. +After we click Save, a new item will appear with a checkbox for completing it, and a button for deleting it. +The list as a whole has a longer lifetime than the individual items.

+

We will implement this by adding and removing Extents from the graph as we add and remove items from our list. +This is a powerful and practical technique that gives Behavior Graph a unique expressiveness in the state management realm.

+

Initial Code

+

We have created a starter project using JSFiddle. +You should use that for this tutorial. +It has some simple HTML/CSS to represent the Todo List’s user interface. +If you wish to use your own environment you will need to copy the HTML and CSS from this JSFiddle site into your own.

+

We first want to set up the initial structure.

+
import * as bg from "https://cdn.skypack.dev/behavior-graph";
+
+class ListExtent extends bg.Extent {
+  constructor(graph) {
+    super(graph);
+
+  }
+}
+
+let graph = new bg.Graph();
+let list = new ListExtent(graph);
+list.addToGraphWithAction();
+

Adding Items

+

New code for you to add or modify will always be highlighted.

+

In order to add a new item,

+
class ListExtent extends bg.Extent {
+  constructor(graph) {
+    super(graph);
+
+    this.save = this.moment();
+    document.querySelector('#save').addEventListener('click', () => {
+      this.save.updateWithAction(document.querySelector('#new-item-text').value);
+    });
+
+    this.behavior()
+      .demands(this.save)
+      .runs(() => {
+      	// do adding here
+      });
+

We create a save moment resource to model the interaction of clicking on the Save button after typing in a new todo. +We use a normal DOM event to call save.updateWithAction() when the button it pressed.

+

Unlike in previous tutorials, with this moment resource we are passing our update method a parameter which contains the value of the text field. +Moments often carry information along with them, in this case we would like to know the textual content of the new item.

+

Next we create an empty behavior, demanding the save resource. +When save is updated, we want this behavior to create a list item and update the UI.

+

What is an Item?

+

A typical way to represent a list item is to create a data structure or object with the relevant data. +We can do something similar with a new Extent subclass.

+
  }
+}
+
+class ItemExtent extends bg.Extent {
+  constructor(graph, text, list) {
+    super(graph);
+    this.list = list;
+    this.itemText = this.state(text);
+  }
+}
+
+let graph = new bg.Graph();
+let list = new ListExtent(graph);
+list.addToGraphWithAction();
+

We add a new ItemExtent subclass and pass in some information into its constructor.

+
    +
  1. A required Graph instance
  2. +
  3. The text of the new todo list item which we store in an itemText state resource
  4. +
  5. A pointer to the parent ListExtent instance which we will use later
  6. +
+

Creating an ItemExtent

+

Back in our ListExtent, inside our behavior we can create an ItemExtent and add it to the graph.

+
    this.behavior()
+      .demands(this.save)
+      .runs(() => {
+        if (this.save.justUpdated) {
+          let item = new ItemExtent(this.graph, this.save.value, this);
+          this.addChildLifetime(item);
+          item.addToGraph();
+        }
+      });
+

We create the new item with the contents of the text field. +Then we call .addChildLifetime(item). +This lets Behavior Graph know that our ListExtent instance will always be around longer than any individual ItemExtent. +This will make it easier to connect behaviors in our ItemExtent to resources in our ListExtent. +We will see more on that later.

+

Next we call item.addToGraph(). +Adding an extent to the graph is a necessary step. +Until we do this, any behaviors or resources in that extent will not perform their expected roles.

+

Collecting the Items

+

We also need a way to keep track of these items as they are added.

+
    this.allItems = this.state([]);
+
+    this.behavior()
+      .supplies(this.allItems)
+      .demands(this.save)
+      .runs(() => {
+        if (this.save.justUpdated) {
+          let item = new ItemExtent(this.graph, this.save.value, this);
+          this.addChildLifetime(item);
+          item.addToGraph();
+          this.allItems.value.push(item);
+          this.allItems.updateForce(this.allItems.value);
+        }
+      });
+

allItems is a state resource initialized with an empty array. +We supply it because we will be updating it inside this behavior. +Whenever we create a new item we will append that ItemExtent instance to the end of that array via its .value property and the built in Array.push() method. +It is typical when working with extents that come and go to store them in a state resource or a collection inside a state resource.

+

Lastly, changing the contents of a collection is not equivalent to calling .update() on the owning resource. +We must update the resource so that demanding behaviors will be notified. +To do this we update the resource with its own contents. +We do this with .updateForce(). +We cannot just call .update() because the contents are still the same array instance. +.update() automatically filters out updates when the old value === the new value. +.updateForce() works identically but ignores this check. +This is a common pattern when storing collections inside a resource.

+

Updating the UI

+

Adding an item still doesn’t update the UI to match. +Inside our ItemExtent we add some code to create a DOM node.

+
class ItemExtent extends bg.Extent {
+  constructor(graph, text, list) {
+    super(graph);
+    this.list = list;
+    this.itemText = this.state(text);
+    this.itemElement = document.querySelector('#templates .list-item').cloneNode(true);
+  }
+}
+

This is a normal property that points to a DOM element we create by cloning some template content inside the existing HTML document. +Then inside our ListExtent behavior we can add our list item UI.

+
      .runs(() => {
+        if (this.save.justUpdated) {
+          let item = new ItemExtent(this.graph, this.save.value, this);
+          this.addChildLifetime(item);
+          item.addToGraph();
+          this.allItems.value.push(item);
+          this.allItems.updateForce(this.allItems.value);
+          this.sideEffect(() => {
+            document.querySelector('#list').appendChild(item.itemElement);
+            document.querySelector('#new-item-text').value = '';
+          });
+        }
+

This side effect adds the DOM element that our new ListExtent instance points to. +It also clears the text field so we can add additional items.

+

Try adding some items by typing in the box and clicking Save. +It seems to add items but we only see empty text. +We can fix that by using our addedToGraph built in resource.

+

Inside ItemExtent a new behavior.

+
    this.itemText = this.state(text);
+    this.itemElement = document.querySelector('#templates .list-item').cloneNode(true);
+
+    this.behavior()
+      .demands(this.itemText, this.addedToGraph)
+      .runs(() => {
+        this.sideEffect(() => {
+          this.itemElement.querySelector('.item-text').innerText = this.itemText.value;
+        });
+      });
+

This behavior will run when the ItemExtent is added to the graph updating its innerText HTML content. +We also added a demand on itemText since we would expect that to change the UI if it ever changes as well. +Now running our code and adding a few items will show our list correctly.

+

Completing Items

+

There’s a checkbox to complete a todo list item. +Checking it at this point does nothing. +Let’s fix that.

+

Inside ItemExtent

+
    this.list = list;
+    this.itemText = this.state(text);
+    this.itemElement = document.querySelector('#templates .list-item').cloneNode(true);
+    this.completed = this.state(false);
+    this.itemElement.querySelector('.completed-checkbox').addEventListener('change', () => {
+      this.completed.updateWithAction(!this.completed.value);
+    });
+

We add a new completed state resource that defaults to false. +We also add a DOM event for when the checkbox is checked so we can update completed.

+

And we add an additional behavior inside ItemExtent

+
    this.behavior()
+      .demands(this.completed, this.addedToGraph)
+      .runs(() => {
+        this.sideEffect(() => {
+          let completedClass = 'completed';
+          if (this.completed.value) {
+            this.itemElement.classList.add(completedClass);
+          } else {
+            this.itemElement.classList.remove(completedClass);
+          }
+        });
+      });
+

This behavior creates a side effect which adds a “completed” class to our HTML item. +This uses the existing CSS to strike-through a completed todo item. +We also include addedToGraph as an additional demand. +It is not strictly necessary at this point because all todo items start off as not completed. +However, it is good practice to use it in behaviors that generate side effects to reflect the current state. +If we were to introduce functionality later for saving and restoring todo lists, we may have items that start in a completed state.

+

Running this and checking/unchecking todo list items should update the UI accordingly.

+

Dynamic Behaviors

+

We will now introduce functionality that takes advantage of Behavior Graph’s ability to dynamically adjust demands and supplies.

+

Remaining Items

+

The “Remaining Items” footer of the UI does not update currently. +First we need it to respond when adding items.

+

Inside ListExtent we add a new behavior.

+
    this.behavior()
+      .demands(this.allItems, this.addedToGraph)
+      .runs(() => {
+        this.sideEffect(() => {
+          let count = this.allItems.value.filter(item => !item.completed.value).length;
+          document.querySelector('#remaining-count').textContent = count;
+        });
+      });
+

This behavior will create a side effect to update the remaining items text to match the current number of non-completed items in the list. +allItems is a demand because we want to run it whenever we add a new item to the list. +Inside the side effect we are able to iterate over the array of ItemExtent instances to check the .value of their completed state resource. +addedToGraph ensures we have the correct starting value in there since it starts out empty.

+

Now try adding a few items to the list and you will see the remaining items count increment.

+

Updating Remaining Items

+

If you try to complete an item however our remaining items count does not change. +This is because that new behavior does not demand the completed resource from our ItemExtent instances. +However, we cannot just add it inside the list of demands because the set of ItemExtent instances changes over time.

+

Behaviors have another clause for handling these situations.

+
    this.behavior()
+      .demands(this.allItems, this.added)
+      .dynamicDemands([this.allItems], () => {
+        return this.allItems.value.map(item => item.completed);
+      })
+      .runs(() => {
+        this.sideEffect(() => {
+          let count = this.allItems.value.filter(item => !item.completed.value).length;
+          document.querySelector('#remaining-count').textContent = count;
+        });
+      });
+

.dynamicDemands() is another clause when creating a behavior that lets you specify an additional list of demands that can change. +It takes two parameters. +The first is an array of resources. +Whenever any of those update, it will run the anonymous function in the second parameter. +That function returns a list of additional demands this behavior should have.

+

Here our dynamic demands clause will return an array containing the completed resource from each ItemExtent instance. +So each time we add a new item, our behavior will adapt so that it will run when the completed resource for that item updates.

+

Now try running the code. +You will see that adding new items updates the remaining items count. +And you will see that checking and unchecking the box on those items affects the remaining count as well.

+

Remaining Items Revisited

+

Its worth a little extra effort to consider what we just did. +The entire remaining items feature is defined by this single behavior.

+

Let’s compare this with a status quo implementation: methods, properties, and objects. +First we might have a method similar to our run block to update the UI

+
// Hypothetical Code -- Don't type this in
+updateRemainingCount() {
+  let count = this.allItems.filter(item => !item.completed).length;
+  document.querySelector('#remaining-count').textContent = count;
+}
+

That seems reasonable, but its not enough. +We need to go inside another method somewhere else in this same class to ensure this gets called when we add a new item. +Perhaps it might look like this:

+
// Hypothetical Code -- Don't type this in
+saveButtonPressed(text) {
+  let save = new Item(text);
+  this.allItems.push(save);
+  this.updateRemainingCount();
+}
+

Ok, so the feature is in two places. +That’s manageable. +Unfortunately, to handle completing, we still need to call in from another place in the code inside the Item class.

+
// Hypothetical Code -- Don't type this in
+completeChecked(checked) {
+  this.completed = checked;
+  this.updateRemainingCount();
+}
+

Now our feature is spread across multiple classes. +And when we add a way to remove items we will need to involve another code-path. +This type of spread out logic is a real challenge for developers. +It is incredibly easy to miss a case.

+

Production software is significantly more complex than this trivial example. +Most developers are swimming in control flows like this. +Behavior Graph lets us collect the “what” and the “why” all together in the same behavior. +The problem literally disappears.

+

Deleting Items

+

We also have a Delete button on each list item which does nothing currently. +We will fix that now.

+

Inside ItemExtent we add some button click handling.

+
    this.itemElement = document.querySelector('#templates .list-item').cloneNode(true);
+    this.completed = this.state(false);
+    this.itemElement.querySelector('.completed-checkbox').addEventListener('change', () => {
+      this.completed.updateWithAction(!this.completed.value);
+    });
+    this.itemElement.querySelector('.item-delete').addEventListener('click', () => {
+      this.list.removeItem.updateWithAction(this);
+    });
+

This takes a DOM event and updates the removeItem resource on ListExtent (which we haven’t added yet). +It is common to interact with resources on other extents and a source of conceptual power. +Here we are saying, “this list item is requesting to be removed.”

+

Note that each ItemExtent’s Delete button updates the same list.removeItem resource. +We are allowed to update resources from multiple actions because only one action will happen during a single event.

+

Now, inside ListExtent,

+
    this.allItems = this.state([]);
+    this.removeItem = this.moment();
+
+    this.behavior()
+      .supplies(this.allItems)
+      .demands(this.save, this.removeItem)
+      .runs(() => {
+        if (this.save.justUpdated) {
+          let item = new ItemExtent(this.graph, this.save.value, this);
+          this.addChildLifetime(item);
+          item.addToGraph();
+          this.allItems.value.push(item);
+          this.allItems.updateForce(this.allItems.value);
+          this.sideEffect(() => {
+            document.querySelector('#list').appendChild(item.itemElement);
+            document.querySelector('#new-item-text').value = '';
+          });
+        } else if (this.removeItem.justUpdated) {
+          let item = this.removeItem.value;
+          item.removeFromGraph();
+          this.allItems.update(this.allItems.value.filter(listItem => listItem !== item));
+          this.sideEffect(() => {
+            document.querySelector('#list').removeChild(item.itemElement);
+          });
+        }
+      });
+

These changes make up the remove item feature. +First we have a new removeItem moment resource. +removeItem models the concept of “a request to be removed happened”. +We add removeItem as an additional demand on our allItems behavior. +This causes the behavior to run when a user clicks on a Delete button.

+

It is common to refer to behaviors by the resources they supply. +This is because a behavior uniquely supplies those resources. +In this case we call this the allItems behavior.

+

We are modifying this behavior because removing an item affects the list in allItems. +We could not put this logic in another behavior because a resource can only be supplied by one behavior. +Updating a resource can only happen in the one behavior that supplies it.

+

Inside the runs block we add new checks for save.justUpdated and removeItem.justUpdated. +It is a common pattern to iterate through .justUpdated checks of the various demands to determine what happened. +In this case we remove the item from the list by building a new list without the item to remove. +So we do not need to call .forceUpdate() like we did when adding the item. +Our side effect ensures that the UI updates as well.

+

Also note that we call.removeFromGraph() on the removed ItemExtent. +Extents should always be removed from the graph if they are no longer needed otherwise their behaviors will continue to run.

+

Remaining Items Re-revisited

+

You may also notice that the remaining items count now goes down if you remove an item that hasn’t been completed yet. +We get this for free because we defined the remaining items on the allItems list. +If we were just using method calls to implement delete, we very likely would have removed the item from our list directly and then had to remember to call some updateRemainingCount() which could have easily been forgotten.

+

This ability to make chances without introducing additional complexity is a hallmark of programming with Behavior Graph. +Once you’ve experienced it a few times you will find it difficult to give up.

+

Editing

+

Now we will introduce some editing functionality. +This will cover some additional uses of dynamic behaviors. +We will allow the user to click on a particular todo list item to select it. +While selected, the user can edit the text inside the main text field.

+

Selecting

+

The first step is to use a DOM event to identify when we have selected a particular item.

+

Inside ItemExtent add another handler.

+
    this.itemElement.querySelector('.item-delete').addEventListener('click', () => {
+      this.list.removeItem.updateWithAction(this);
+    });
+    this.itemElement.querySelector('.item-text').addEventListener('click', () => {
+    	this.list.selectRequest.updateWithAction(this);
+    });
+

selectRequest updates with the list item that was clicked as its .value.

+

Inside ListExtent we add the related resources and a corresponding behavior.

+
    this.allItems = this.state([]);
+    this.removeItem = this.moment();
+    this.selectRequest = this.moment();
+    this.selected = this.state(null);
+
    this.behavior()
+      .supplies(this.selected)
+      .demands(this.selectRequest)
+      .runs(() => {
+      	this.selected.update(this.selectRequest.value);
+      });
+

Clicking on an item sets our new selected resource as the item that was just clicked.

+

Selected

+

Now we want our items to visually reflect when they are selected. +We can do this by demanding this resource in a behavior in each ItemExtent.

+
	this.behavior()
+      .demands(this.list.selected)
+      .runs(() => {
+      	let selected = this.list.selected.value === this;
+        this.sideEffect(() => {
+          let selectedClass = 'selected'
+          if (selected) {
+          	this.itemElement.classList.add(selectedClass);
+          } else {
+            this.itemElement.classList.remove(selectedClass);
+          }
+        });
+      });
+

When the selected state resource inside ListExtent updates, this behavior on every item will run. +They each demand this.list.selected. +Depending on if the item is the one that is selected we will change the UI accordingly.

+

We want to refer back to the beginning where we called .addChildLifetime(item) inside ListExtent.

+
          let item = new ItemExtent(this.graph, this.save.value, this);
+          this.addChildLifetime(item);
+          item.addToGraph();
+

This line says that the list will always be around when the item is. +This gives us permission to add this.list.selected, a resource in ListExtent, as a demand on the behavior inside each ItemExtent. +Behavior Graph ensures that we don’t link to resources that may no longer be part of the graph and it uses lifetimes as a way to manage that.

+

You can now try out this code by clicking on different items.

+

Notice that we can take a list of many items and click on different ones and watch it switch. +Each time, one of those behaviors adds the ‘selected’ CSS class while all the rest remove the ‘selected’ class. +Removing a class when its already not there is valid and simplifies our logic.

+

Deselect

+

Its easy enough to introduce deselecting by clicking on the already selected element.

+

Inside ListExtent we modify our selected behavior.

+
    this.behavior()
+      .supplies(this.selected)
+      .demands(this.selectRequest)
+      .runs(() => {
+      	if (this.selected.value == this.selectRequest.value) {
+          this.selected.update(null);
+        } else {
+        	this.selected.update(this.selectRequest.value);      
+        }
+      });
+

We check if the currently selected item is the one that was just clicked on and set it to null in that case. +This communicates that nothing should be selected. +Try running now and clicking on an item multiple times.

+

Updating The Text Field

+

Now we want to introduce editing. +Let’s try updating the main text field when we select an item so we can edit it.

+
    this.behavior()
+      .supplies(this.selected)
+      .demands(this.selectRequest)
+      .runs(() => {
+      	if (this.selected.value == this.selectRequest.value) {
+          this.selected.update(null);
+        } else {
+        	this.selected.update(this.selectRequest.value);      
+        }
+        
+        if (this.selected.justUpdated) {
+          this.sideEffect(() => {
+            let textField = document.querySelector('#new-item-text');
+            textField.value = this.selected.value === null ? '' : this.selected.value.itemText.value;
+            let actionText = document.querySelector('#action');
+            actionText.innerText = this.selected.value === null ? 'Add' : 'Edit'
+          });
+        }
+      });
+

Whenever selected updates, we run this new side effect. +It copies over the text of the item into the text field. +It also updates the UI to indicate that we are editing and not adding.

+

Conversely, when selected updates to null, it puts our UI state back to an Add mode.

+

Preventing Adding

+

When we are in editing mode, the save button should cause the text in our item to update. +However right now it will still create a new item. +We want to prevent that from happening when we are in editing mode.

+
    this.behavior()
+      .supplies(this.allItems)
+      .demands(this.save, this.removeItem)
+      .runs(() => {
+        if (this.save.justUpdated && this.selected.traceValue === null) {
+          let item = new ItemExtent(this.graph, this.save.value, this);
+          this.addChildLifetime(item);
+          item.addToGraph();
+          this.allItems.value.push(item);
+

At the time we click the Save button, we want to know if we are in editing mode or not. +We could check selected.value to see if it is null (ie not editing). +However, here we use selected.traceValue instead. +.traceValue is the value of the resource at the beginning of the graph event (the instant the action started). +So if selected updates this event, .traceValue will still return what it was before it changed.

+

This also removes the requirement that we demand selected in this behavior. +Here we just care if an item is already selected or not, not that something was “just selected”. +So we don’t need it as a demand. +.traceValue of any resource is always accessible by any behavior without demanding (or supplying) it.

+

The if check ignores the save click when there’s something already selected.

+

Making Changes

+

Now we can add a new behavior inside ListExtent that responds to our save and updates the text of the selected item.

+
        }
+      });
+      
+    this.behavior()
+      .dynamicSupplies([this.allItems], () => {
+        return this.allItems.value.map(item => item.itemText);
+      })
+      .demands(this.save)
+      .runs(() => {
+      	if (this.save.justUpdated && this.selected.traceValue !== null) {
+          this.selected.traceValue.itemText.update(this.save.value);
+        }
+      });
+      
+    this.behavior()
+      .demands(this.allItems, this.addedToGraph)
+

This new behavior uses .dyanmicSupplies(). +This is a clause we haven’t seen before. +It does work similarly to .dynamicDemands(). +In this behavior, we update our supplies to be the itemText resource from each ItemExtent instance. +Whenever we add our remove an item, this behavior will update its supplies.

+

We will supply all of them because any one of them might become selected. +When the user clicks the Save button, this behavior will update the itemText on the selected item to whats inside the text field.

+

Notice that we use selected.traceValue again here, so it is not part of the demands. +We want which item was selected at the time save was updated. +We also do not need this behavior to run when selected updates.

+

Notice that all we do is update itemText. +We already have a behavior that knows how to change that UI when we change the text. +It is common to make these kinds of changes and see everything work as expected.

+

Run the code and you will see your working todo list.

+

Challenge

+

After saving our changes, the item remains selected. +It might be a better user experience to exit editing mode after saving. +Can you implement this?

+

Try your best before looking at the answer.

+

Hints:

+
    +
  1. You can do this by modifying a single behavior.
  2. +
  3. Which behavior is responsible for selected?
  4. +
  5. Which resource updates when we click the Save button?
  6. +
+

Answer: Clearing Post Save

+

We can modify our selected behavior inside ListExtent.

+
    this.behavior()
+      .supplies(this.selected)
+      .demands(this.selectRequest, this.save)
+      .runs(() => {
+      	if (this.selectRequest.justUpdated) {
+      	  if (this.selected.value == this.selectRequest.value) {
+            this.selected.update(null);
+          } else {
+          	this.selected.update(this.selectRequest.value);      
+          }        
+        } else if (this.save.justUpdated) {
+          this.selected.update(null);
+        }
+

Now our selected behavior also runs and deselects the current item when the Save button is pressed. +Here see again the common pattern of checking various resources' .justUpdated property inside a behavior.

+

Just before adding this feature we used selected.traceValue in a few behaviors. +This change here is an additional motivation for that. +If we used selected.value in those behaviors it means they would demand selected which is supplied by this behavior. +Which means they would run after this behavior. +Which means by they time they ran, selected.value would be null. +We don’t want what selected changes to, we want what it was at the start. +This is what traceValue provides.

+

Congratulations

+

Congratulations! You have completed the third tutorial. +You can see the finished tutorial code here.

+ + + + +
+ + +
+
+
+ +
+
+
+
+ +
+
+ +
+
+ © 2022 Yahoo All Rights Reserved + + + + +
+
+
+
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/typescript/webfonts/fa-brands-400.eot b/docs/typescript/webfonts/fa-brands-400.eot new file mode 100644 index 0000000..2cca660 Binary files /dev/null and b/docs/typescript/webfonts/fa-brands-400.eot differ diff --git a/docs/typescript/webfonts/fa-brands-400.svg b/docs/typescript/webfonts/fa-brands-400.svg new file mode 100644 index 0000000..d9939bc --- /dev/null +++ b/docs/typescript/webfonts/fa-brands-400.svg @@ -0,0 +1,3451 @@ + + + + + +Created by FontForge 20190112 at Fri Aug 2 14:41:09 2019 + By Robert Madole +Copyright (c) Font Awesome + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/typescript/webfonts/fa-brands-400.ttf b/docs/typescript/webfonts/fa-brands-400.ttf new file mode 100644 index 0000000..2cb180b Binary files /dev/null and b/docs/typescript/webfonts/fa-brands-400.ttf differ diff --git a/docs/typescript/webfonts/fa-brands-400.woff b/docs/typescript/webfonts/fa-brands-400.woff new file mode 100644 index 0000000..e192c51 Binary files /dev/null and b/docs/typescript/webfonts/fa-brands-400.woff differ diff --git a/docs/typescript/webfonts/fa-brands-400.woff2 b/docs/typescript/webfonts/fa-brands-400.woff2 new file mode 100644 index 0000000..e916d75 Binary files /dev/null and b/docs/typescript/webfonts/fa-brands-400.woff2 differ diff --git a/docs/typescript/webfonts/fa-regular-400.eot b/docs/typescript/webfonts/fa-regular-400.eot new file mode 100644 index 0000000..54c8991 Binary files /dev/null and b/docs/typescript/webfonts/fa-regular-400.eot differ diff --git a/docs/typescript/webfonts/fa-regular-400.svg b/docs/typescript/webfonts/fa-regular-400.svg new file mode 100644 index 0000000..e04c2e0 --- /dev/null +++ b/docs/typescript/webfonts/fa-regular-400.svg @@ -0,0 +1,803 @@ + + + + + +Created by FontForge 20190112 at Fri Aug 2 14:41:09 2019 + By Robert Madole +Copyright (c) Font Awesome + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/typescript/webfonts/fa-regular-400.ttf b/docs/typescript/webfonts/fa-regular-400.ttf new file mode 100644 index 0000000..ef43cfd Binary files /dev/null and b/docs/typescript/webfonts/fa-regular-400.ttf differ diff --git a/docs/typescript/webfonts/fa-regular-400.woff b/docs/typescript/webfonts/fa-regular-400.woff new file mode 100644 index 0000000..13f0191 Binary files /dev/null and b/docs/typescript/webfonts/fa-regular-400.woff differ diff --git a/docs/typescript/webfonts/fa-regular-400.woff2 b/docs/typescript/webfonts/fa-regular-400.woff2 new file mode 100644 index 0000000..004b29b Binary files /dev/null and b/docs/typescript/webfonts/fa-regular-400.woff2 differ diff --git a/docs/typescript/webfonts/fa-solid-900.eot b/docs/typescript/webfonts/fa-solid-900.eot new file mode 100644 index 0000000..8f11368 Binary files /dev/null and b/docs/typescript/webfonts/fa-solid-900.eot differ diff --git a/docs/typescript/webfonts/fa-solid-900.svg b/docs/typescript/webfonts/fa-solid-900.svg new file mode 100644 index 0000000..b80d477 --- /dev/null +++ b/docs/typescript/webfonts/fa-solid-900.svg @@ -0,0 +1,4649 @@ + + + + + +Created by FontForge 20190112 at Fri Aug 2 14:41:09 2019 + By Robert Madole +Copyright (c) Font Awesome + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/typescript/webfonts/fa-solid-900.ttf b/docs/typescript/webfonts/fa-solid-900.ttf new file mode 100644 index 0000000..5a6d747 Binary files /dev/null and b/docs/typescript/webfonts/fa-solid-900.ttf differ diff --git a/docs/typescript/webfonts/fa-solid-900.woff b/docs/typescript/webfonts/fa-solid-900.woff new file mode 100644 index 0000000..d92df45 Binary files /dev/null and b/docs/typescript/webfonts/fa-solid-900.woff differ diff --git a/docs/typescript/webfonts/fa-solid-900.woff2 b/docs/typescript/webfonts/fa-solid-900.woff2 new file mode 100644 index 0000000..df7e704 Binary files /dev/null and b/docs/typescript/webfonts/fa-solid-900.woff2 differ diff --git a/docs/typescript/why-behavior-graph/index.html b/docs/typescript/why-behavior-graph/index.html new file mode 100644 index 0000000..62f7fcc --- /dev/null +++ b/docs/typescript/why-behavior-graph/index.html @@ -0,0 +1,328 @@ + + + + + + + + + + + + + + + + + + + + +Why Behavior Graph? | Behavior Graph + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+
+
+
+ + +
+ + + + + +
+

Why Behavior Graph?

+ + +

Behavior Graph is a software library that greatly enhances our ability to program user facing software and control systems. Programs of this type quickly scale up in complexity as features are added. Behavior Graph directly addresses this complexity by shifting more of the burden to the computer. +It works by offering the programmer a new unit of code organization called a behavior. +Behaviors are blocks of code enriched with additional information about their stateful relationships. +Using this information, Behavior Graph enforces safe use of mutable state, arguably the primary source of complexity in this class of software. +It does this by taking on the responsibility of control flow between behaviors, ensuring they are are run at the correct time and in the correct order.

+

Interactive Systems

+

It helps to understand why user facing software, control systems, and similar programs present a particular challenge.

+

We define these systems by three primary characteristics:

+
    +
  1. Asynchronous: inputs can happen over a period of time and at any time
  2. +
  3. Event-driven: outputs occur over time in response to inputs
  4. +
  5. Stateful: outputs depend on a history of prior inputs
  6. +
+

A thermostat controlling the temperature in a house is an example:

+

Thermostat

+
    +
  1. It runs continuously, responding to temperature changes as well as button presses in order to operate the heating equipment.
  2. +
  3. Button presses will result in changes to the display.
  4. +
  5. Button presses which set the desired temperature will determine when the heating equipment turns on in the future.
  6. +
+

The challenge comes from the large number of different inputs where order and history matter. +A sequence of 10 presses on our Up and Down buttons can occur in over 1000 different ways. +An interface that accepts 10 different types of input over a sequence of 10 events means we are facing 10 billion possible arrangements. +And that is a tiny fraction of what a real user facing application is typically up against.

+

The solution comes from the fact that we only need to remember just enough information to make decisions in the future. +Instead of remembering each button press, we simply remember a desired temperature and update it as inputs happen. +We don’t care which sequence of button presses gets us to 68 degrees. +To our program they are all the same. +We call this compressed historical information state. +With state we can compress 10 billion button presses into a single number.

+

Inputs lead to state changes. +Pressing the Up and Down button changes the desired temperature state. +State changes lead to outputs. +Changing the desired temperature means the display will change. +State changes also often lead to other state changes as our program grows in features. +When the desired temperature changes, the desired state of the heating equipment may change. +(And when that desired state of the heating equipment changes, our program will output to turn on or off the heating equipment.)

+

A correctly functioning program will have a natural dependency graph between inputs, internal states, and outputs. +Unfortunately, status quo programming techniques have no way of expressing this dependency graph directly. +Programmers must implicitly build this graph out of the correct sequencing of method calls and state updates. +In so doing, they throw away this valuable dependency information and the computer can no longer help us. +That is the root of the problem.

+

Behavior Graph

+

With Behavior Graph, we build our programs out of units of functionality called behaviors. +Behaviors manage state via components called resources. +Behaviors are simple, easily understood blocks of code paired with any relationships to these resources. +Resources are objects which encapsulate both state and how that state changes. +A behavior for our thermostat would be “when the user presses the Up or Down buttons, increase or decrease the desired temperature by one degree.” +The desired temperature is the resource that this behavior manages.

+

Desired Temperature

+

An entire thermostat program would be built out of many of these behaviors. +So we add a second behavior, “when the current temperature is below the desired temperature, turn on the heating equipment.” +Our behaviors will collaborate to implement the complete thermostat functionality without knowing about each other directly. +Instead, behaviors compose via resources, in this case desired temperature. +The first behavior declares that it is responsible for setting the desired temperature. +The second behavior declares that it uses the desired temperature to know if it needs to turn on the heat.

+

Heating

+

We never run behaviors directly by calling them like we do with methods. +Instead Behavior Graph uses the dependencies between behaviors and resources to determine which behaviors need to run and in which order. +If the user presses the Up button to raise the desired temperature above the current temperature, the heating behavior will automatically run after the temperature behavior updates the desired temperature resource.

+

Here we can see the contrast to the status quo approach of nesting chains of method calls. +In order to ensure the heat can be turned on when the up button is pressed, the button press method needs to call the desired temperature setting method. +And that method in turn needs to call the heating equipment method. +Because no method runs unless another method calls it, we must explicitly weave these threads of control flow throughout our code. +In large programs, separately maintaining control flow to ensure our dependency graph is respected is both difficult and error prone.

+

Fred Brooks famously pointed out that software is necessarily complex because the problems themselves are complex. +With Behavior Graph we overcome our human complexity limits by delegating more of that work to the computer itself. +As programmers, we focus on individual behaviors and their immediate relationships. +The computer in turn handles the complex chore of sorting through hundreds or thousands of those behaviors to ensure a working program.

+

Behavior Graph gives us control flow for free.

+

Behavior Graph is a compact and mature library with no external dependencies. +It is used in production applications with millions of daily users. +It is available for multiple languages and platforms (Objective C/Swift, Typescript/Javascript, Kotlin).

+ + + + +
+ + +
+
+
+ +
+
+
+
+ +
+
+ +
+
+ © 2022 Yahoo All Rights Reserved + + + + +
+
+
+
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..34d45c4 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,1573 @@ +{ + "name": "bgdocs", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "devDependencies": { + "autoprefixer": "^10.4.0", + "postcss": "^8.4.5", + "postcss-cli": "^9.1.0" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/anymatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", + "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", + "dev": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/array-union": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-3.0.1.tgz", + "integrity": "sha512-1OvF9IbWwaeiM9VhzYXVQacMibxpXOMYVNIvMtKRyX9SImBXpKcFr8XvFDeEslCyuH/t6KRt7HEO94AlP8Iatw==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/autoprefixer": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.0.tgz", + "integrity": "sha512-7FdJ1ONtwzV1G43GDD0kpVMn/qbiNqyOPMFTX5nRffI+7vgWoFEc6DcXOxHJxrWNDXrZh18eDsZjvZGUljSRGA==", + "dev": true, + "dependencies": { + "browserslist": "^4.17.5", + "caniuse-lite": "^1.0.30001272", + "fraction.js": "^4.1.1", + "normalize-range": "^0.1.2", + "picocolors": "^1.0.0", + "postcss-value-parser": "^4.1.0" + }, + "bin": { + "autoprefixer": "bin/autoprefixer" + }, + "engines": { + "node": "^10 || ^12 || >=14" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.19.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.19.1.tgz", + "integrity": "sha512-u2tbbG5PdKRTUoctO3NBD8FQ5HdPh1ZXPHzp1rwaa5jTc+RV9/+RlWiAIKmjRPQF+xbGM9Kklj5bZQFa2s/38A==", + "dev": true, + "dependencies": { + "caniuse-lite": "^1.0.30001286", + "electron-to-chromium": "^1.4.17", + "escalade": "^3.1.1", + "node-releases": "^2.0.1", + "picocolors": "^1.0.0" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001294", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001294.tgz", + "integrity": "sha512-LiMlrs1nSKZ8qkNhpUf5KD0Al1KCBE3zaT7OLOwEkagXMEDij98SiOovn9wxVGQpklk9vVC/pUSqgYmkmKOS8g==", + "dev": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + } + }, + "node_modules/chokidar": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.2.tgz", + "integrity": "sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ==", + "dev": true, + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/dependency-graph": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/dependency-graph/-/dependency-graph-0.11.0.tgz", + "integrity": "sha512-JeMq7fEshyepOWDfcfHK06N3MhyPhz++vtqWhMT5O9A3K42rdsEDpfdVqjaqaAhsw6a+ZqeDvQVtD0hFHQWrzg==", + "dev": true, + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.4.29", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.29.tgz", + "integrity": "sha512-N2Jbwxo5Rum8G2YXeUxycs1sv4Qme/ry71HG73bv8BvZl+I/4JtRgK/En+ST/Wh/yF1fqvVCY4jZBgMxnhjtBA==", + "dev": true + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/fast-glob": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.7.tgz", + "integrity": "sha512-rYGMRwip6lUMvYD3BTScMwT1HtAs2d71SMv66Vrxs0IekGZEjhM0pcMfjQPnknBt2zeCwQMEupiN02ZP4DiT1Q==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/fastq": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", + "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/fraction.js": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.1.2.tgz", + "integrity": "sha512-o2RiJQ6DZaR/5+Si0qJUIy637QMRudSi9kU/FFzx9EZazrIdnBgpU+3sEWCxAVhH2RtxW2Oz+T4p2o8uOPVcgA==", + "dev": true, + "engines": { + "node": "*" + }, + "funding": { + "type": "patreon", + "url": "https://www.patreon.com/infusion" + } + }, + "node_modules/fs-extra": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.0.0.tgz", + "integrity": "sha512-C5owb14u9eJwizKGdchcDUQeFtlSHHthBk8pbX9Vc1PFZrLombudjDnNns88aYslCyF6IY5SUw3Roz6xShcEIQ==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-stdin": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-9.0.0.tgz", + "integrity": "sha512-dVKBjfWisLAicarI2Sf+JuBE/DghV4UzNAVe9yhEJuzeREd3JhOTE9cUaJTeSa77fsbQUK3pcOpJfM59+VKZaA==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/globby": { + "version": "12.0.2", + "resolved": "https://registry.npmjs.org/globby/-/globby-12.0.2.tgz", + "integrity": "sha512-lAsmb/5Lww4r7MM9nCCliDZVIKbZTavrsunAsHLr9oHthrZP1qi7/gAnHOsUs9bLvEt2vKVJhHmxuL7QbDuPdQ==", + "dev": true, + "dependencies": { + "array-union": "^3.0.1", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.7", + "ignore": "^5.1.8", + "merge2": "^1.4.1", + "slash": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.8.tgz", + "integrity": "sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==", + "dev": true + }, + "node_modules/ignore": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", + "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/import-cwd/-/import-cwd-3.0.0.tgz", + "integrity": "sha512-4pnzH16plW+hgvRECbDWpQl3cqtvSofHWh44met7ESfZ8UZOWWddm8hEyDTqREJ9RbYHY8gi8DqmaelApoOGMg==", + "dev": true, + "dependencies": { + "import-from": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/import-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/import-from/-/import-from-3.0.0.tgz", + "integrity": "sha512-CiuXOFFSzkU5x/CR0+z7T91Iht4CXgfCxVOFRhh2Zyhg5wOpWvvDLQUsWl+gcN+QscYBjez8hDCt85O7RLDttQ==", + "dev": true, + "dependencies": { + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/lilconfig": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.0.4.tgz", + "integrity": "sha512-bfTIN7lEsiooCocSISTWXkiWJkRqtL9wYtYy+8EK3Y41qh3mpwPU0ycTOgjdY9ErwXCc8QyrQp82bdL0Xkm9yA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", + "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", + "dev": true, + "dependencies": { + "braces": "^3.0.1", + "picomatch": "^2.2.3" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/nanoid": { + "version": "3.1.30", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.30.tgz", + "integrity": "sha512-zJpuPDwOv8D2zq2WRoMe1HsfZthVewpel9CAvTfc/2mBD1uUT/agc5f7GHGWXlYkFvi1mVxe4IjvP2HNrop7nQ==", + "dev": true, + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/node-releases": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.1.tgz", + "integrity": "sha512-CqyzN6z7Q6aMeF/ktcMVTzhAHCEpf8SOarwpzpf8pNBY2k5/oM34UHldUwp8VKI7uxct2HxSRdJjBaZeESzcxA==", + "dev": true + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/normalize-range": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", + "integrity": "sha1-LRDAa9/TEuqXd2laTShDlFa3WUI=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true + }, + "node_modules/picomatch": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", + "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postcss": { + "version": "8.4.5", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.5.tgz", + "integrity": "sha512-jBDboWM8qpaqwkMwItqTQTiFikhs/67OYVvblFFTM7MrZjt6yMKd6r2kgXizEbTTljacm4NldIlZnhbjr84QYg==", + "dev": true, + "dependencies": { + "nanoid": "^3.1.30", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + } + }, + "node_modules/postcss-cli": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/postcss-cli/-/postcss-cli-9.1.0.tgz", + "integrity": "sha512-zvDN2ADbWfza42sAnj+O2uUWyL0eRL1V+6giM2vi4SqTR3gTYy8XzcpfwccayF2szcUif0HMmXiEaDv9iEhcpw==", + "dev": true, + "dependencies": { + "chokidar": "^3.3.0", + "dependency-graph": "^0.11.0", + "fs-extra": "^10.0.0", + "get-stdin": "^9.0.0", + "globby": "^12.0.0", + "picocolors": "^1.0.0", + "postcss-load-config": "^3.0.0", + "postcss-reporter": "^7.0.0", + "pretty-hrtime": "^1.0.3", + "read-cache": "^1.0.0", + "slash": "^4.0.0", + "yargs": "^17.0.0" + }, + "bin": { + "postcss": "index.js" + }, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "postcss": "^8.0.0" + } + }, + "node_modules/postcss-load-config": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-3.1.0.tgz", + "integrity": "sha512-ipM8Ds01ZUophjDTQYSVP70slFSYg3T0/zyfII5vzhN6V57YSxMgG5syXuwi5VtS8wSf3iL30v0uBdoIVx4Q0g==", + "dev": true, + "dependencies": { + "import-cwd": "^3.0.0", + "lilconfig": "^2.0.3", + "yaml": "^1.10.2" + }, + "engines": { + "node": ">= 10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + "peerDependencies": { + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "ts-node": { + "optional": true + } + } + }, + "node_modules/postcss-reporter": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/postcss-reporter/-/postcss-reporter-7.0.5.tgz", + "integrity": "sha512-glWg7VZBilooZGOFPhN9msJ3FQs19Hie7l5a/eE6WglzYqVeH3ong3ShFcp9kDWJT1g2Y/wd59cocf9XxBtkWA==", + "dev": true, + "dependencies": { + "picocolors": "^1.0.0", + "thenby": "^1.3.4" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "dev": true + }, + "node_modules/pretty-hrtime": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz", + "integrity": "sha1-t+PqQkNaTJsnWdmeDyAesZWALuE=", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/read-cache": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", + "integrity": "sha1-5mTvMRYRZsl1HNvo28+GtftY93Q=", + "dev": true, + "dependencies": { + "pify": "^2.3.0" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/slash": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz", + "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/source-map-js": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.1.tgz", + "integrity": "sha512-4+TN2b3tqOCd/kaGRJ/sTYA0tR0mdXx26ipdolxcwtJVqEnqNYvlCAt1q3ypy4QMlYus+Zh34RNtYLoq2oQ4IA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/thenby": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/thenby/-/thenby-1.3.4.tgz", + "integrity": "sha512-89Gi5raiWA3QZ4b2ePcEwswC3me9JIg+ToSgtE0JWeCynLnLxNr/f9G+xfo9K+Oj4AFdom8YNJjibIARTJmapQ==", + "dev": true + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", + "dev": true, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/yargs": { + "version": "17.3.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.3.1.tgz", + "integrity": "sha512-WUANQeVgjLbNsEmGk20f+nlHgOqzRFpiGWVaBrYGYIGANIIu3lWjoyi0fNlFmJkvfhCZ6BXINe7/W2O2bV4iaA==", + "dev": true, + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.0.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.0.0.tgz", + "integrity": "sha512-z9kApYUOCwoeZ78rfRYYWdiU/iNL6mwwYlkkZfJoyMR1xps+NEBX5X7XmRpxkZHhXJ6+Ey00IwKxBBSW9FIjyA==", + "dev": true, + "engines": { + "node": ">=12" + } + } + }, + "dependencies": { + "@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "requires": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + } + }, + "@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true + }, + "@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "requires": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + } + }, + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "anymatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", + "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", + "dev": true, + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, + "array-union": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-3.0.1.tgz", + "integrity": "sha512-1OvF9IbWwaeiM9VhzYXVQacMibxpXOMYVNIvMtKRyX9SImBXpKcFr8XvFDeEslCyuH/t6KRt7HEO94AlP8Iatw==", + "dev": true + }, + "autoprefixer": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.0.tgz", + "integrity": "sha512-7FdJ1ONtwzV1G43GDD0kpVMn/qbiNqyOPMFTX5nRffI+7vgWoFEc6DcXOxHJxrWNDXrZh18eDsZjvZGUljSRGA==", + "dev": true, + "requires": { + "browserslist": "^4.17.5", + "caniuse-lite": "^1.0.30001272", + "fraction.js": "^4.1.1", + "normalize-range": "^0.1.2", + "picocolors": "^1.0.0", + "postcss-value-parser": "^4.1.0" + } + }, + "binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "dev": true + }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "requires": { + "fill-range": "^7.0.1" + } + }, + "browserslist": { + "version": "4.19.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.19.1.tgz", + "integrity": "sha512-u2tbbG5PdKRTUoctO3NBD8FQ5HdPh1ZXPHzp1rwaa5jTc+RV9/+RlWiAIKmjRPQF+xbGM9Kklj5bZQFa2s/38A==", + "dev": true, + "requires": { + "caniuse-lite": "^1.0.30001286", + "electron-to-chromium": "^1.4.17", + "escalade": "^3.1.1", + "node-releases": "^2.0.1", + "picocolors": "^1.0.0" + } + }, + "caniuse-lite": { + "version": "1.0.30001294", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001294.tgz", + "integrity": "sha512-LiMlrs1nSKZ8qkNhpUf5KD0Al1KCBE3zaT7OLOwEkagXMEDij98SiOovn9wxVGQpklk9vVC/pUSqgYmkmKOS8g==", + "dev": true + }, + "chokidar": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.2.tgz", + "integrity": "sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ==", + "dev": true, + "requires": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "fsevents": "~2.3.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + } + }, + "cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "dependency-graph": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/dependency-graph/-/dependency-graph-0.11.0.tgz", + "integrity": "sha512-JeMq7fEshyepOWDfcfHK06N3MhyPhz++vtqWhMT5O9A3K42rdsEDpfdVqjaqaAhsw6a+ZqeDvQVtD0hFHQWrzg==", + "dev": true + }, + "dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "requires": { + "path-type": "^4.0.0" + } + }, + "electron-to-chromium": { + "version": "1.4.29", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.29.tgz", + "integrity": "sha512-N2Jbwxo5Rum8G2YXeUxycs1sv4Qme/ry71HG73bv8BvZl+I/4JtRgK/En+ST/Wh/yF1fqvVCY4jZBgMxnhjtBA==", + "dev": true + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true + }, + "fast-glob": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.7.tgz", + "integrity": "sha512-rYGMRwip6lUMvYD3BTScMwT1HtAs2d71SMv66Vrxs0IekGZEjhM0pcMfjQPnknBt2zeCwQMEupiN02ZP4DiT1Q==", + "dev": true, + "requires": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + } + }, + "fastq": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", + "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", + "dev": true, + "requires": { + "reusify": "^1.0.4" + } + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "fraction.js": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.1.2.tgz", + "integrity": "sha512-o2RiJQ6DZaR/5+Si0qJUIy637QMRudSi9kU/FFzx9EZazrIdnBgpU+3sEWCxAVhH2RtxW2Oz+T4p2o8uOPVcgA==", + "dev": true + }, + "fs-extra": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.0.0.tgz", + "integrity": "sha512-C5owb14u9eJwizKGdchcDUQeFtlSHHthBk8pbX9Vc1PFZrLombudjDnNns88aYslCyF6IY5SUw3Roz6xShcEIQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + } + }, + "fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "optional": true + }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true + }, + "get-stdin": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-9.0.0.tgz", + "integrity": "sha512-dVKBjfWisLAicarI2Sf+JuBE/DghV4UzNAVe9yhEJuzeREd3JhOTE9cUaJTeSa77fsbQUK3pcOpJfM59+VKZaA==", + "dev": true + }, + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + }, + "globby": { + "version": "12.0.2", + "resolved": "https://registry.npmjs.org/globby/-/globby-12.0.2.tgz", + "integrity": "sha512-lAsmb/5Lww4r7MM9nCCliDZVIKbZTavrsunAsHLr9oHthrZP1qi7/gAnHOsUs9bLvEt2vKVJhHmxuL7QbDuPdQ==", + "dev": true, + "requires": { + "array-union": "^3.0.1", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.7", + "ignore": "^5.1.8", + "merge2": "^1.4.1", + "slash": "^4.0.0" + } + }, + "graceful-fs": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.8.tgz", + "integrity": "sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==", + "dev": true + }, + "ignore": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", + "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", + "dev": true + }, + "import-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/import-cwd/-/import-cwd-3.0.0.tgz", + "integrity": "sha512-4pnzH16plW+hgvRECbDWpQl3cqtvSofHWh44met7ESfZ8UZOWWddm8hEyDTqREJ9RbYHY8gi8DqmaelApoOGMg==", + "dev": true, + "requires": { + "import-from": "^3.0.0" + } + }, + "import-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/import-from/-/import-from-3.0.0.tgz", + "integrity": "sha512-CiuXOFFSzkU5x/CR0+z7T91Iht4CXgfCxVOFRhh2Zyhg5wOpWvvDLQUsWl+gcN+QscYBjez8hDCt85O7RLDttQ==", + "dev": true, + "requires": { + "resolve-from": "^5.0.0" + } + }, + "is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "requires": { + "binary-extensions": "^2.0.0" + } + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, + "is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true + }, + "jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6", + "universalify": "^2.0.0" + } + }, + "lilconfig": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.0.4.tgz", + "integrity": "sha512-bfTIN7lEsiooCocSISTWXkiWJkRqtL9wYtYy+8EK3Y41qh3mpwPU0ycTOgjdY9ErwXCc8QyrQp82bdL0Xkm9yA==", + "dev": true + }, + "merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true + }, + "micromatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", + "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", + "dev": true, + "requires": { + "braces": "^3.0.1", + "picomatch": "^2.2.3" + } + }, + "nanoid": { + "version": "3.1.30", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.30.tgz", + "integrity": "sha512-zJpuPDwOv8D2zq2WRoMe1HsfZthVewpel9CAvTfc/2mBD1uUT/agc5f7GHGWXlYkFvi1mVxe4IjvP2HNrop7nQ==", + "dev": true + }, + "node-releases": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.1.tgz", + "integrity": "sha512-CqyzN6z7Q6aMeF/ktcMVTzhAHCEpf8SOarwpzpf8pNBY2k5/oM34UHldUwp8VKI7uxct2HxSRdJjBaZeESzcxA==", + "dev": true + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true + }, + "normalize-range": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", + "integrity": "sha1-LRDAa9/TEuqXd2laTShDlFa3WUI=", + "dev": true + }, + "path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true + }, + "picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true + }, + "picomatch": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", + "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", + "dev": true + }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + }, + "postcss": { + "version": "8.4.5", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.5.tgz", + "integrity": "sha512-jBDboWM8qpaqwkMwItqTQTiFikhs/67OYVvblFFTM7MrZjt6yMKd6r2kgXizEbTTljacm4NldIlZnhbjr84QYg==", + "dev": true, + "requires": { + "nanoid": "^3.1.30", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.1" + } + }, + "postcss-cli": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/postcss-cli/-/postcss-cli-9.1.0.tgz", + "integrity": "sha512-zvDN2ADbWfza42sAnj+O2uUWyL0eRL1V+6giM2vi4SqTR3gTYy8XzcpfwccayF2szcUif0HMmXiEaDv9iEhcpw==", + "dev": true, + "requires": { + "chokidar": "^3.3.0", + "dependency-graph": "^0.11.0", + "fs-extra": "^10.0.0", + "get-stdin": "^9.0.0", + "globby": "^12.0.0", + "picocolors": "^1.0.0", + "postcss-load-config": "^3.0.0", + "postcss-reporter": "^7.0.0", + "pretty-hrtime": "^1.0.3", + "read-cache": "^1.0.0", + "slash": "^4.0.0", + "yargs": "^17.0.0" + } + }, + "postcss-load-config": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-3.1.0.tgz", + "integrity": "sha512-ipM8Ds01ZUophjDTQYSVP70slFSYg3T0/zyfII5vzhN6V57YSxMgG5syXuwi5VtS8wSf3iL30v0uBdoIVx4Q0g==", + "dev": true, + "requires": { + "import-cwd": "^3.0.0", + "lilconfig": "^2.0.3", + "yaml": "^1.10.2" + } + }, + "postcss-reporter": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/postcss-reporter/-/postcss-reporter-7.0.5.tgz", + "integrity": "sha512-glWg7VZBilooZGOFPhN9msJ3FQs19Hie7l5a/eE6WglzYqVeH3ong3ShFcp9kDWJT1g2Y/wd59cocf9XxBtkWA==", + "dev": true, + "requires": { + "picocolors": "^1.0.0", + "thenby": "^1.3.4" + } + }, + "postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "dev": true + }, + "pretty-hrtime": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz", + "integrity": "sha1-t+PqQkNaTJsnWdmeDyAesZWALuE=", + "dev": true + }, + "queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true + }, + "read-cache": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", + "integrity": "sha1-5mTvMRYRZsl1HNvo28+GtftY93Q=", + "dev": true, + "requires": { + "pify": "^2.3.0" + } + }, + "readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "requires": { + "picomatch": "^2.2.1" + } + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "dev": true + }, + "resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true + }, + "reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true + }, + "run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "requires": { + "queue-microtask": "^1.2.2" + } + }, + "slash": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz", + "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==", + "dev": true + }, + "source-map-js": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.1.tgz", + "integrity": "sha512-4+TN2b3tqOCd/kaGRJ/sTYA0tR0mdXx26ipdolxcwtJVqEnqNYvlCAt1q3ypy4QMlYus+Zh34RNtYLoq2oQ4IA==", + "dev": true + }, + "string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.1" + } + }, + "thenby": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/thenby/-/thenby-1.3.4.tgz", + "integrity": "sha512-89Gi5raiWA3QZ4b2ePcEwswC3me9JIg+ToSgtE0JWeCynLnLxNr/f9G+xfo9K+Oj4AFdom8YNJjibIARTJmapQ==", + "dev": true + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "requires": { + "is-number": "^7.0.0" + } + }, + "universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", + "dev": true + }, + "wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + } + }, + "y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true + }, + "yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "dev": true + }, + "yargs": { + "version": "17.3.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.3.1.tgz", + "integrity": "sha512-WUANQeVgjLbNsEmGk20f+nlHgOqzRFpiGWVaBrYGYIGANIIu3lWjoyi0fNlFmJkvfhCZ6BXINe7/W2O2bV4iaA==", + "dev": true, + "requires": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.0.0" + } + }, + "yargs-parser": { + "version": "21.0.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.0.0.tgz", + "integrity": "sha512-z9kApYUOCwoeZ78rfRYYWdiU/iNL6mwwYlkkZfJoyMR1xps+NEBX5X7XmRpxkZHhXJ6+Ey00IwKxBBSW9FIjyA==", + "dev": true + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..fe6dd68 --- /dev/null +++ b/package.json @@ -0,0 +1,7 @@ +{ + "devDependencies": { + "autoprefixer": "^10.4.0", + "postcss": "^8.4.5", + "postcss-cli": "^9.1.0" + } +}