From 235b9d13b9d74aed8dc79e75bd161638806d11cb Mon Sep 17 00:00:00 2001 From: <> Date: Fri, 8 Dec 2023 18:14:52 +0000 Subject: [PATCH] Deployed 3dc6143 with MkDocs version: 1.5.3 --- .nojekyll | 0 404.html | 1233 ++ CNAME | 1 + about/index.html | 1276 ++ api-docs/CHANGELOG/index.html | 6111 +++++++++ api-docs/assets/postman-auth.png | Bin 0 -> 124259 bytes api-docs/development/Libraries/index.html | 1708 +++ api-docs/development/Release/index.html | 1462 ++ api-docs/development/Structure/index.html | 1494 ++ api-docs/development/Testing/index.html | 2018 +++ api-docs/development/index.html | 1360 ++ api-docs/index.html | 1319 ++ api-docs/usage/API Reference/index.html | 11302 ++++++++++++++++ api-docs/usage/Authentication/index.html | 1509 +++ api-docs/usage/Configuration/index.html | 1435 ++ api-docs/usage/Deployment/index.html | 1591 +++ api-docs/usage/OpenAPI/index.html | 1280 ++ api-docs/usage/Overview/index.html | 1550 +++ api-docs/usage/Permissions/index.html | 1440 ++ api-docs/usage/Quick Start/index.html | 1433 ++ api-docs/usage/index.html | 1265 ++ assets/favicon.ico | Bin 0 -> 4286 bytes assets/images/favicon.png | Bin 0 -> 1870 bytes assets/javascripts/bundle.d7c377c4.min.js | 29 + assets/javascripts/bundle.d7c377c4.min.js.map | 7 + assets/javascripts/lunr/min/lunr.ar.min.js | 1 + assets/javascripts/lunr/min/lunr.da.min.js | 18 + assets/javascripts/lunr/min/lunr.de.min.js | 18 + assets/javascripts/lunr/min/lunr.du.min.js | 18 + assets/javascripts/lunr/min/lunr.el.min.js | 1 + assets/javascripts/lunr/min/lunr.es.min.js | 18 + assets/javascripts/lunr/min/lunr.fi.min.js | 18 + assets/javascripts/lunr/min/lunr.fr.min.js | 18 + assets/javascripts/lunr/min/lunr.he.min.js | 1 + assets/javascripts/lunr/min/lunr.hi.min.js | 1 + assets/javascripts/lunr/min/lunr.hu.min.js | 18 + assets/javascripts/lunr/min/lunr.hy.min.js | 1 + assets/javascripts/lunr/min/lunr.it.min.js | 18 + assets/javascripts/lunr/min/lunr.ja.min.js | 1 + assets/javascripts/lunr/min/lunr.jp.min.js | 1 + assets/javascripts/lunr/min/lunr.kn.min.js | 1 + assets/javascripts/lunr/min/lunr.ko.min.js | 1 + assets/javascripts/lunr/min/lunr.multi.min.js | 1 + assets/javascripts/lunr/min/lunr.nl.min.js | 18 + assets/javascripts/lunr/min/lunr.no.min.js | 18 + assets/javascripts/lunr/min/lunr.pt.min.js | 18 + assets/javascripts/lunr/min/lunr.ro.min.js | 18 + assets/javascripts/lunr/min/lunr.ru.min.js | 18 + assets/javascripts/lunr/min/lunr.sa.min.js | 1 + .../lunr/min/lunr.stemmer.support.min.js | 1 + assets/javascripts/lunr/min/lunr.sv.min.js | 18 + assets/javascripts/lunr/min/lunr.ta.min.js | 1 + assets/javascripts/lunr/min/lunr.te.min.js | 1 + assets/javascripts/lunr/min/lunr.th.min.js | 1 + assets/javascripts/lunr/min/lunr.tr.min.js | 18 + assets/javascripts/lunr/min/lunr.vi.min.js | 1 + assets/javascripts/lunr/min/lunr.zh.min.js | 1 + assets/javascripts/lunr/tinyseg.js | 206 + assets/javascripts/lunr/wordcut.js | 6708 +++++++++ .../workers/search.f886a092.min.js | 42 + .../workers/search.f886a092.min.js.map | 7 + assets/logo.png | Bin 0 -> 12294 bytes assets/logo.svg | 181 + assets/stylesheets/main.45e1311d.min.css | 1 + assets/stylesheets/main.45e1311d.min.css.map | 1 + assets/stylesheets/palette.06af60db.min.css | 1 + .../stylesheets/palette.06af60db.min.css.map | 1 + index.html | 1263 ++ sitemap.xml | 3 + sitemap.xml.gz | Bin 0 -> 127 bytes termynal.css | 133 + termynal.js | 275 + web-app-docs/development/index.html | 1262 ++ web-app-docs/index.html | 1265 ++ web-app-docs/usage/Quick Start/index.html | 1354 ++ web-app-docs/usage/index.html | 1264 ++ 76 files changed, 55077 insertions(+) create mode 100644 .nojekyll create mode 100644 404.html create mode 100644 CNAME create mode 100644 about/index.html create mode 100644 api-docs/CHANGELOG/index.html create mode 100644 api-docs/assets/postman-auth.png create mode 100644 api-docs/development/Libraries/index.html create mode 100644 api-docs/development/Release/index.html create mode 100644 api-docs/development/Structure/index.html create mode 100644 api-docs/development/Testing/index.html create mode 100644 api-docs/development/index.html create mode 100644 api-docs/index.html create mode 100644 api-docs/usage/API Reference/index.html create mode 100644 api-docs/usage/Authentication/index.html create mode 100644 api-docs/usage/Configuration/index.html create mode 100644 api-docs/usage/Deployment/index.html create mode 100644 api-docs/usage/OpenAPI/index.html create mode 100644 api-docs/usage/Overview/index.html create mode 100644 api-docs/usage/Permissions/index.html create mode 100644 api-docs/usage/Quick Start/index.html create mode 100644 api-docs/usage/index.html create mode 100644 assets/favicon.ico create mode 100644 assets/images/favicon.png create mode 100644 assets/javascripts/bundle.d7c377c4.min.js create mode 100644 assets/javascripts/bundle.d7c377c4.min.js.map create mode 100644 assets/javascripts/lunr/min/lunr.ar.min.js create mode 100644 assets/javascripts/lunr/min/lunr.da.min.js create mode 100644 assets/javascripts/lunr/min/lunr.de.min.js create mode 100644 assets/javascripts/lunr/min/lunr.du.min.js create mode 100644 assets/javascripts/lunr/min/lunr.el.min.js create mode 100644 assets/javascripts/lunr/min/lunr.es.min.js create mode 100644 assets/javascripts/lunr/min/lunr.fi.min.js create mode 100644 assets/javascripts/lunr/min/lunr.fr.min.js create mode 100644 assets/javascripts/lunr/min/lunr.he.min.js create mode 100644 assets/javascripts/lunr/min/lunr.hi.min.js create mode 100644 assets/javascripts/lunr/min/lunr.hu.min.js create mode 100644 assets/javascripts/lunr/min/lunr.hy.min.js create mode 100644 assets/javascripts/lunr/min/lunr.it.min.js create mode 100644 assets/javascripts/lunr/min/lunr.ja.min.js create mode 100644 assets/javascripts/lunr/min/lunr.jp.min.js create mode 100644 assets/javascripts/lunr/min/lunr.kn.min.js create mode 100644 assets/javascripts/lunr/min/lunr.ko.min.js create mode 100644 assets/javascripts/lunr/min/lunr.multi.min.js create mode 100644 assets/javascripts/lunr/min/lunr.nl.min.js create mode 100644 assets/javascripts/lunr/min/lunr.no.min.js create mode 100644 assets/javascripts/lunr/min/lunr.pt.min.js create mode 100644 assets/javascripts/lunr/min/lunr.ro.min.js create mode 100644 assets/javascripts/lunr/min/lunr.ru.min.js create mode 100644 assets/javascripts/lunr/min/lunr.sa.min.js create mode 100644 assets/javascripts/lunr/min/lunr.stemmer.support.min.js create mode 100644 assets/javascripts/lunr/min/lunr.sv.min.js create mode 100644 assets/javascripts/lunr/min/lunr.ta.min.js create mode 100644 assets/javascripts/lunr/min/lunr.te.min.js create mode 100644 assets/javascripts/lunr/min/lunr.th.min.js create mode 100644 assets/javascripts/lunr/min/lunr.tr.min.js create mode 100644 assets/javascripts/lunr/min/lunr.vi.min.js create mode 100644 assets/javascripts/lunr/min/lunr.zh.min.js create mode 100644 assets/javascripts/lunr/tinyseg.js create mode 100644 assets/javascripts/lunr/wordcut.js create mode 100644 assets/javascripts/workers/search.f886a092.min.js create mode 100644 assets/javascripts/workers/search.f886a092.min.js.map create mode 100644 assets/logo.png create mode 100644 assets/logo.svg create mode 100644 assets/stylesheets/main.45e1311d.min.css create mode 100644 assets/stylesheets/main.45e1311d.min.css.map create mode 100644 assets/stylesheets/palette.06af60db.min.css create mode 100644 assets/stylesheets/palette.06af60db.min.css.map create mode 100644 index.html create mode 100644 sitemap.xml create mode 100644 sitemap.xml.gz create mode 100644 termynal.css create mode 100644 termynal.js create mode 100644 web-app-docs/development/index.html create mode 100644 web-app-docs/index.html create mode 100644 web-app-docs/usage/Quick Start/index.html create mode 100644 web-app-docs/usage/index.html diff --git a/.nojekyll b/.nojekyll new file mode 100644 index 0000000..e69de29 diff --git a/404.html b/404.html new file mode 100644 index 0000000..54a654f --- /dev/null +++ b/404.html @@ -0,0 +1,1233 @@ + + + + + + + + + + + + + + + + + + + University Polling + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ +

404 - Not found

+ +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/CNAME b/CNAME new file mode 100644 index 0000000..287cb3d --- /dev/null +++ b/CNAME @@ -0,0 +1 @@ +docs.unipoll.cc \ No newline at end of file diff --git a/about/index.html b/about/index.html new file mode 100644 index 0000000..539c3b6 --- /dev/null +++ b/about/index.html @@ -0,0 +1,1276 @@ + + + + + + + + + + + + + + + + + + + + + + + About - University Polling + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + Skip to content + + +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

This is API Documentation

+

The API repository WIKI pages are linked as submodule to Docs repository. +Thus, any updates to WIKI should be synced with MkDocs.

+ + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/api-docs/CHANGELOG/index.html b/api-docs/CHANGELOG/index.html new file mode 100644 index 0000000..99206a0 --- /dev/null +++ b/api-docs/CHANGELOG/index.html @@ -0,0 +1,6111 @@ + + + + + + + + + + + + + + + + + + + + + + + Changelog - University Polling + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + Skip to content + + +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

CHANGELOG

+

v0.12.2 (2023-12-08)

+

Chore

+
    +
  • chore: Fixed mypy linting (42e6e4a)
  • +
+

Ci

+
    +
  • +

    ci: Fixed file name (66b2835)

    +
  • +
  • +

    ci: Changed artifact download path (15c2f41)

    +
  • +
  • +

    ci: Added trigger on changelog update (3197245)

    +
  • +
  • +

    ci: Updated changelog workflow (4c98e25)

    +
  • +
  • +

    ci: update (f8cd7b3)

    +
  • +
  • +

    ci: update (7d897f9)

    +
  • +
  • +

    ci: updated git installation step (04f002c)

    +
  • +
  • +

    ci: fixed needs (4f552fb)

    +
  • +
  • +

    ci: Changed test ci (acd9969)

    +
  • +
  • +

    ci: Changed workflow name (1c6a2e6)

    +
  • +
  • +

    ci: Added workflow to test (442fa8f)

    +
  • +
  • +

    ci: Update docs job (73f6975)

    +
  • +
  • +

    ci: app_id and private_key deprecated (3e3692d)

    +
  • +
+

Fix

+
    +
  • fix: Fixed get and create polls actions (b9bdc72)
  • +
+

Refactor

+
    +
  • +

    refactor: Resolved mypy issues caused by original_field (73aa72b)

    +
  • +
  • +

    refactor: Changed Poll document

    +
  • +
+

Replace workspace Link with BackLink, removed redundant declarations (394a16e)

+

Style

+
    +
  • +

    style: Fixed flake8 errors (5390021)

    +
  • +
  • +

    style: Removed extra spaces (1531b13)

    +
  • +
+

Unknown

+
    +
  • Merge branch 'main' of github.com:unipoll/API (ff0de73)
  • +
+

v0.12.1 (2023-10-23)

+

Fix

+
    +
  • fix: Changed policy_holder_type for new policies
  • +
+

The policy_holder_type was set to "member", updated the method to use type of policy_holder via get_document_type() method (6f595ff)

+

Refactor

+
    +
  • refactor: Changed argument type in ErrorWhileRemovingMember
  • +
+

Changed user: Account to member: Member (4301c36)

+

Unknown

+
    +
  • Merge pull request #78 from unipoll/members
  • +
+

Patch Policies (a5100c0)

+

v0.12.0 (2023-10-23)

+

Feature

+
    +
  • feat: Added Member document (8199204)
  • +
+

Fix

+
    +
  • +

    fix: Removed PathOperations import (1cbfc93)

    +
  • +
  • +

    fix: Updated group request to get policies

    +
  • +
+

Updated route get_group_policies to find member using dependency and use it for get_policies action (c16a981)

+

Refactor

+
    +
  • +

    refactor: Fixed mypy issues (d6ec5b8)

    +
  • +
  • +

    refactor: Added get_document_type classmethod

    +
  • +
+

Added classmethod to Beanie Document get_document_type which returns Document type as a string (cfeebf7)

+
    +
  • +

    refactor: Updated to accommodate member update (73e4017)

    +
  • +
  • +

    refactor: Deleted obsolete path_operations file

    +
  • +
+

This file included functions to read actions for building permissions and check permissions based on operation_id, both functions are not obsolete (095c103)

+

Style

+
    +
  • +

    style: flake8 (b08c103)

    +
  • +
  • +

    style: Updated comments

    +
  • +
+

Changed account to member (d29213a)

+

Test

+
    +
  • +

    test: Updated tests to use new member document (8f7f352)

    +
  • +
  • +

    test: Updated workspace tests due to member update (af1dd25)

    +
  • +
+

Unknown

+
    +
  • Merge pull request #77 from unipoll/members
  • +
+

Updated Members (102afff)

+
    +
  • Update README.md
  • +
+

Fixed link to developer wiki (a521dac)

+

v0.11.3 (2023-10-17)

+

Ci

+
    +
  • ci: Added job to trigger docs workflow
  • +
+

On release, the api release workflow will trigger workflow in the docs repository with event update_api_changelog (c68bd48)

+

Fix

+
    +
  • fix: Fixed delete actions of Workspace/Group
  • +
+

Due to changed to policies, upon deletion of Workspace/Group the related Policies could not be fetched and therefore deleted. Using DBref, the updated actions find and delete policies without even fetching them first (764cd57)

+
    +
  • fix: Updated policy as a workaround for #75
  • +
+

A workaround for issue #75, the parent_resource was converted to the Link type, which is manually populated using create_link() method. Since Beanie cannot/struggles to fetch links of multiple types, two new class methods were added: get_parent_resource() uses link reference to find and return parent document(Workspace/Group/Poll), and get_policy_holder() finds and returns document of policy holder(Account/Group). (7ac8180)

+
    +
  • fix: Changed the default permission for new group
  • +
+

Replaced GROUP_BASIC_PERMISSIONS with WORKSPACE_BASIC_PERMISSIONS (ff0a65f)

+

Refactor

+
    +
  • +

    refactor: Fixed mypy issues (8cb2916)

    +
  • +
  • +

    refactor: Changed remove_policy method

    +
  • +
+

Renamed remove_policy to remove_member_policy, and added new remove_policy method which takes policy as an argument (ddfe048)

+

Style

+
    +
  • style: Fixed resource spelling (6ffa917)
  • +
+

Test

+
    +
  • test: Styling
  • +
+

Provided query parameter using params argument instead of passing as a part of url string (d4f986c)

+
    +
  • test: Fixed set_permission_test
  • +
+

Added account_id parameter when checking account permissions (b68a4b1)

+

Unknown

+
    +
  • Merge pull request #76 from unipoll/development
  • +
+

Policies Patch (697406d)

+
    +
  • +

    Untrack .vscode (3885ec1)

    +
  • +
  • +

    Update README.md

    +
  • +
+

Updated Postman Documentation link (9d17121)

+
    +
  • Merge branch 'main' of github.com:unipoll/API (f60d80b)
  • +
+

v0.11.2 (2023-10-15)

+

Fix

+
    +
  • fix: Fixed routes to get/update policies
  • +
+

Updated Policy endpoints in Workspace and Group routes: Added account_id query parameter to GET resource/{resource_id}/policies, deleted GET resource/{resource_id}/policy, changed PUT resource/{resource_id}/policy to resource/{resource_id}/policies/{policy_id} and removed all the conditions inside (3404c17)

+

Test

+
    +
  • test: Updated policies in workspace/group tests
  • +
+

Updated tests to accomodate workspace/group route changes to get/update policies (b65dc01)

+

Unknown

+
    +
  • Merge pull request #74 from unipoll/development
  • +
+

Updated get/update policies routes (6a950e6)

+

v0.11.1 (2023-10-13)

+

Ci

+
    +
  • ci: Update postman.yaml
  • +
+

Changed vars.POSTMAN_API_ID to secrets.POSTMAN_API_ID (9c34ea9)

+

Fix

+
    +
  • +

    fix: Added comma to workspace permission list (166184d)

    +
  • +
  • +

    fix: Updated set policy routes

    +
  • +
+

Added case when user does not provide account_id in update_policy request, with the else statement, the route will find current user's policy (f072769)

+
    +
  • fix: Replace required permission for update_policy
  • +
+

Changed old permission set_policy to the new update_policies (edccfa9)

+
    +
  • fix: updated get_policies_from_resource
  • +
+

check_permissions does not return anything but raises an exception in case user does not have the required permission, so the check must be made using try-catch block (c116990)

+
    +
  • fix: Changed required permission
  • +
+

Changed required permissions from add_members to get_members (785b889)

+
    +
  • fix: Resolved issue with not getting group
  • +
+

check_permissions raises UserNotAuthorized from ResourceExceptions, so even though the permission is checked inside workspace, it will not raise WorkspaceExceptions (97808c3)

+
    +
  • fix: Resolved circular import (e5eb703)
  • +
+

Refactor

+
    +
  • +

    refactor: resolved mypy issues (762fa14)

    +
  • +
  • +

    refactor: Added permission check to actions

    +
  • +
+

Added permission check to actions using new check_permission function (3b83508)

+
    +
  • refactor: Updated dependencies functions
  • +
+

Removed permission check dependencies, added http wrapper for resource accessors (05db0f0)

+
    +
  • refactor: Updated Permissions
  • +
+

Updated permission names, added utility function check_permissions which checks if user has required permissions based on provided resource and permission requirements, renamed check_permission to compare_permissions (4451376)

+
    +
  • refactor: Removed permission check based on operation_id (5bd9b3b)
  • +
+

Style

+
    +
  • style: flake8 styling (44a7dce)
  • +
+

Test

+
    +
  • test: Change group test
  • +
+

The new policy action will return the users policy even if the user does not have permission to get_policies (d4d7980)

+

Unknown

+
    +
  • Merge pull request #73 from unipoll/permissions
  • +
+

Overhaul of Permission System (5e0ed7d)

+

v0.11.0 (2023-10-12)

+

Feature

+
    +
  • +

    feat: Added dependency to get policy by ID (0bfeb6d)

    +
  • +
  • +

    feat: Moved policy related actions to a separate file (5129fbe)

    +
  • +
  • +

    feat: Added new routes to get and create groups

    +
  • +
+

Added new route to get list of groups, by default returns all groups which a user has permission to view, the endpoint also accepts query parameters to filter list of groups by name, workspace, or account (ff9aa02)

+

Fix

+
    +
  • +

    fix: Typing errors (9d9cc23)

    +
  • +
  • +

    fix: Resolved typing errors (9a852b3)

    +
  • +
  • +

    fix: Delete policies when group is deleted (a157480)

    +
  • +
  • +

    fix: Fixed groups not deleting (504b92f)

    +
  • +
+

Refactor

+
    +
  • refactor: Added request schema for new group route
  • +
+

Added GroupCreateRequest for new POST /groups endpoint that will replace workspace/{id}/groups (f74f844)

+
    +
  • +

    refactor: Add permission check to get_policy (924e462)

    +
  • +
  • +

    refactor: Changed imports (dd7ba5a)

    +
  • +
  • +

    refactor: Moved create poll action (2664b7a)

    +
  • +
  • +

    refactor: Changed Member Actions

    +
  • +
+

Moved Members related actions to a separate module. The old routes use new actions to view, add, remove members from Group/Workspace (3bd5363)

+
    +
  • refactor: Moved group actions
  • +
+

Moved actions to get list of groups and create new group to GroupActions (6fdd25e)

+

Style

+ +

Unknown

+
    +
  • Merge pull request #72 from unipoll/actions_rework
  • +
+

Actions overhaull (b843563)

+ +

v0.10.0 (2023-10-07)

+

Build

+
    +
  • +

    build: Updated Dockerfile to use new cli run command (ea53b88)

    +
  • +
  • +

    build: Cleanup (95c9d05)

    +
  • +
  • +

    build: Updated pydantic version to 2.4 (91a5a30)

    +
  • +
+

Chore

+
    +
  • +

    chore: Added .vscode to ignore (8cbac9f)

    +
  • +
  • +

    chore: deleted postman folder (0803c81)

    +
  • +
+

Ci

+
    +
  • +

    ci: Fixed api-path-to-file-name (d55ee22)

    +
  • +
  • +

    ci: Changed action (cfc742a)

    +
  • +
  • +

    ci: Fixed action input

    +
  • +
+

Unexpected input 'swaggerPath', changed to 'openApiSpec' (d74fa8b)

+
    +
  • +

    ci: Upadated postman workflow (598d729)

    +
  • +
  • +

    ci: Added workflow to update docs repository

    +
  • +
+

On any updated to api wiki pages it will trigger Update Sobmodule workflow in the docs repository which will update the api-docs submodule refference (41349d1)

+

Feature

+
    +
  • +

    feat: Added docker-compose file (ee2756e)

    +
  • +
  • +

    feat: Added new cli options

    +
  • +
+

Added option to setup app and get openapi schema (c7bd5b8)

+

Fix

+
    +
  • fix: Fixed admin default in config (51f81a1)
  • +
+

Refactor

+
    +
  • refactor: Improved succes messages
  • +
+

Added full paths to the file for setup and get-openapi commands (2c29aac)

+

Style

+
    +
  • style: fixed flake8 issues (41f5339)
  • +
+

Unknown

+
    +
  • Merge pull request #71 from unipoll/development
  • +
+

Pydantic 2, better cli, docker-compose (44d071a)

+
    +
  • Merge pull request #70 from unipoll/pydantic2-migration
  • +
+

build: Updated pydantic version to 2.4 (9c541ee)

+

v0.9.0 (2023-10-04)

+

Build

+
    +
  • build: Changed python base image to 3.11-alpine (0d44ba0)
  • +
+

Feature

+
    +
  • feat: Added action to get poll list (114616f)
  • +
+

Fix

+
    +
  • fix: Changed permissions field type
  • +
+

Changed permissions field type in Pollicy document from Permissions to int (9c44d6d)

+

Refactor

+
    +
  • refactor: Changed main.py
  • +
+

Added src to pythonpath, change main function to use app.run() (8b76639)

+
    +
  • refactor: Changed Dockerfile
  • +
+

Change build process to add unipoll-api entry point (210452d)

+
    +
  • refactor: Changed Policy workspace link
  • +
+

Replace link to workspace with a backlink to parent resource that holds list of policies (581249f)

+
    +
  • refactor: Added PolicyHolderNotFound exceptions
  • +
+

Added PolicyHolderNotFound exceptions instead of using generic resource exception (804ad38)

+
    +
  • refactor: Moved permission checks
  • +
+

Moved permission checks to appropriate actions (fd2e23c)

+
    +
  • refactor: Created Policy Actions file
  • +
+

Moved actions to get policy/policies to a separate file, the client can specify the resource from which the policy list is requested or the user whose policy is requested (6c89b10)

+

Style

+
    +
  • +

    style: Removed commented out code (48733e1)

    +
  • +
  • +

    style: Renamed mongo database

    +
  • +
+

Renamed mongo database from app to unipoll-api (bcd412d)

+

Test

+
    +
  • +

    test: linting (46dd4e8)

    +
  • +
  • +

    test: Added back the testpaths field

    +
  • +
+

Without testpaths, pytest would rund tests from dependency modules (03e71a8)

+

Unknown

+
    +
  • Merge pull request #69 from unipoll/development
  • +
+

Development (2590487)

+
    +
  • Merge pull request #68 from unipoll/permissions
  • +
+

Permissions (077d92d)

+
    +
  • Merge pull request #67 from unipoll/development
  • +
+

Renamed database and updated Dockerfile (3513d97)

+
    +
  • Merge branch 'main' into development (839dfdf)
  • +
+

v0.8.3 (2023-09-26)

+

Ci

+
    +
  • ci: Updated tag list for semantic-release (075c1ff)
  • +
+

Fix

+
    +
  • +

    fix: Removed unreachable return statement (e8df4da)

    +
  • +
  • +

    fix: Typing

    +
  • +
+

Specified type of router and open_router for mypy (eb97462)

+ +

Refactor

+
    +
  • refactor: Moved query parsing to actions
  • +
+

Query parameters are passed to actions functions as parameters, where the response model is built

+

Closes #65 (38fc8f0)

+
    +
  • refactor: Updated imports (e47a414)
  • +
+

Style

+
    +
  • style: renamed DOCUMENT_MODELS to documentModels (86a1269)
  • +
+

Unknown

+
    +
  • Merge pull request #66 from unipoll/development
  • +
+

Minor updates, ci, style, and refactoring (6361e35)

+

v0.8.2 (2023-09-24)

+

Fix

+
    +
  • fix: Fix missing commas in PollPermissions list (9550a8f)
  • +
+

Unknown

+
    +
  • Merge pull request #64 from unipoll/development
  • +
+

fix: Fix missing commas in PollPermissions list (b38c3e2)

+
    +
  • Update README.md
  • +
+

Updated badges (d808620)

+
    +
  • Update README.md
  • +
+

Updated GitHub release Badge (5ea3db2)

+ +

v0.8.1 (2023-09-22)

+

Build

+
    +
  • build: Excluded tests folder from distribution
  • +
+

Added Manifest.in and slightely changed project configuration to exclude tests folder from the distribution which was causing import error (7483101)

+

Fix

+
    +
  • fix: Fixed docker host ip
  • +
+

Changed host ip from 127.0.0.1 to 0.0.0.0 which was preventing connections from outside (0f8d89b)

+

Unknown

+
    +
  • revert: Removed minor flag
  • +
+

Removed option forcing updating minor versionh (0150b96)

+
    +
  • Update README.md
  • +
+

Changed API to api in badge links (5dc4129)

+

v0.8.0 (2023-09-21)

+

Ci

+
    +
  • ci: Forcing minor version updated due to error (0cf6e85)
  • +
+

Fix

+
    +
  • fix: Add ref main to checkout actions (ae7753a)
  • +
+

v0.7.10 (2023-09-21)

+

Breaking

+
    +
  • build: Moved source module to unipoll_api
  • +
+

BREAKING CHANGE: Changed project structure (49c2aa0)

+

Ci

+
    +
  • +

    ci: Update releaes trigger (5f36871)

    +
  • +
  • +

    ci: Updated PyPI release job to use GiHub runner (070a60a)

    +
  • +
  • +

    ci: Deleted pypi workflow (bba484a)

    +
  • +
  • +

    ci: Testing PYPI API Token with self hosted runner (cd283b2)

    +
  • +
  • +

    ci: Testing a different runner for PyPI release (57eb4a1)

    +
  • +
  • +

    ci: Fixed the name of the workflow (15450fd)

    +
  • +
  • +

    ci: Added separate workflow action for pypi release (0c8fee2)

    +
  • +
+

Feature

+
    +
  • feat: Added issue auto labeler workflow
  • +
+

The new workflow will automaticaly assign labels based on keywords in title (257beab)

+
    +
  • +

    feat: Added routes to update and delete polls (766fd63)

    +
  • +
  • +

    feat: Add actions to update and delete poll (6bc7310)

    +
  • +
+

Fix

+
    +
  • +

    fix: Fixed path to version.py (cc085db)

    +
  • +
  • +

    fix: TypeError: HEAD is a detached symbolic reference on PR

    +
  • +
+

This is a general problem with CI services that checkout the repo by commit hash - because PSR has to create a new commit to update versions etc, it needs a branch to commit that to. (1e830dc)

+
    +
  • +

    fix: Fixed branch name from dev to development (04a01b4)

    +
  • +
  • +

    fix: Linting and checking validity of types (9d2bba3)

    +
  • +
  • +

    fix: Changed username to user (83c18b7)

    +
  • +
+

Refactor

+
    +
  • refactor: Changed package structure for building distribution
  • +
+

Moved source module to unopoll_api module inside of src, added argparser to main and run functions, added entry point for the project, fixed pyproject.toml and Dockerfile, fixed all imports

+

closes #57 (63deb00)

+
    +
  • refactor: Updated Poll Schemas naming
  • +
+

Added CreatePollRequest and UpdatePollRequest schemas, renamed Poll schema to PollResponse (afaf278)

+

Test

+
    +
  • test: Fixed pytest and tox issues for unipoll_api module
  • +
+

Added new file test-requirements.txt with deppendencies for tox, specified project layout for testing, removed redundant TestClient and cleaned up imports in the test files (6506d21)

+

Unknown

+
    +
  • Merge pull request #63 from unipoll/development
  • +
+

Minor CI Updates (1c00df0)

+
    +
  • Merge pull request #61 from unipoll/development
  • +
+

Development merged (42d40fa)

+
    +
  • Merge pull request #60 from unipoll/build
  • +
+

Updated Project Structure for PyPI release (53a06ca)

+
    +
  • Merge pull request #59 from unipoll/labels-workflow
  • +
+

feat: Added issue auto labeler workflow (e7cbf92)

+
    +
  • Merge pull request #58 from unipoll/polls
  • +
+

Polls (93bb0d7)

+
    +
  • Merge branch 'main' of github.com:unipoll/API (281450b)
  • +
+

v0.7.9 (2023-09-18)

+

Ci

+
    +
  • ci: Added checkout step to PyPI release job (2f61e81)
  • +
+

Unknown

+
    +
  • Merge branch 'main' of github.com:unipoll/API (ba57603)
  • +
+

v0.7.8 (2023-09-18)

+

Fix

+
    +
  • fix: Added matrix to pypi release step (629f080)
  • +
+

v0.7.7 (2023-09-18)

+

Build

+
    +
  • build: Changed name to unipoll-api (ffe4b80)
  • +
+

Ci

+
    +
  • ci: Updated PyPI release step (4bbf66c)
  • +
+

v0.7.6 (2023-09-18)

+

Ci

+
    +
  • +

    ci: Fixed released condition for pypi job (e100810)

    +
  • +
  • +

    ci: Added step to publish package to PyPI (441bd3a)

    +
  • +
  • +

    ci: Added test trigger on pull into main (df99d9e)

    +
  • +
  • +

    ci: Removed debug message from release step (aef429c)

    +
  • +
  • +

    ci: Added test as a requirement for release action (b91ff0a)

    +
  • +
+

Unknown

+
    +
  • Update README.md
  • +
+

Updated tests badge (d8ee875)

+
    +
  • Update README.md
  • +
+

Changed color of version badge (9c0e7c7)

+
    +
  • +

    Merge branch 'main' of github.com:unipoll/API (a79a75b)

    +
  • +
  • +

    Update README.md

    +
  • +
+

Added badges for GitHub release and Docker Image (5be3a4a)

+

v0.7.5 (2023-09-17)

+

Ci

+
    +
  • ci: Updated actions
  • +
+

Added test job to release action, deleted docker action as it's moved to release, updated trigger for tests actions (93423ad)

+

v0.7.4 (2023-09-17)

+

Ci

+
    +
  • ci: Added id to the release step (19bcc00)
  • +
+

v0.7.3 (2023-09-17)

+

Ci

+
    +
  • ci: Testing output variables without brackets (4d9894e)
  • +
+

v0.7.2 (2023-09-17)

+

Build

+
    +
  • +

    build: Removed package_data as not supported (46e9ea2)

    +
  • +
  • +

    build: Updated pyproject.toml

    +
  • +
+

Removed setuptools_scm, provided version manualy, updated email (67cd4a8)

+

Ci

+
    +
  • ci: Updated release action
  • +
+

Added debug message to see the output variables, changed docker tag from output.tag to output.version (eb989c0)

+

v0.7.1 (2023-09-17)

+

Breaking

+
    +
  • feat: Updated Polls
  • +
+

Updated polls document deffinition and schemas for polls and questions

+

BREAKING CHANGE: Added Polls (f2bc01d)

+

Ci

+
    +
  • +

    ci: Removed matrix value (48304f8)

    +
  • +
  • +

    ci: Updated release action

    +
  • +
+

Added build command and forced patch version (08ede08)

+
    +
  • +

    ci: Made jobs run sequentially (f912c06)

    +
  • +
  • +

    ci: Updated release actions

    +
  • +
+

Added additional step to rebuild package manualy, added job to release Docker image using release output (937f218)

+

Feature

+
    +
  • +

    feat: Added route to get Poll by id (56b12d8)

    +
  • +
  • +

    feat: Created actions to get questions and policies (6670083)

    +
  • +
  • +

    feat: Added model and permission dependencies for Polls

    +
  • +
+

Added get_poll_model dependency to get a poll by id and verify it exists, and check_poll_permission to check if the current user has permissions to access the poll and perform requested actions (89eac3b)

+
    +
  • feat: Created permission class and parser for Polls
  • +
+

Created PollPermissions class from action file, added constants POLL_ALL_PERMISSIONS and POLL_BASIC_PERMISSIONS (6f3a866)

+
    +
  • feat: Added exceptions for getting polls
  • +
+

Added exceptions PollNotFound, UserNotAuthorized, and ActionNotFound (e0e3a84)

+
    +
  • +

    feat: Created QuestionList schema (486d2e2)

    +
  • +
  • +

    feat: Updated schemas

    +
  • +
+

Added public and workspace field to Poll schema (7669106)

+
    +
  • +

    feat: Added public field to Poll documents (3d64638)

    +
  • +
  • +

    feat: Added response scheme PollShort

    +
  • +
+

Changed PollList scheme to exclude questions and policies fields (08a9645)

+
    +
  • feat: Updated workspace resource
  • +
+

Added Polls definitions to workspace routes, schemas, and actions (e0f2611)

+
    +
  • +

    feat: Created Poll scheme (67bb557)

    +
  • +
  • +

    feat: Created Question scheme (c7e9b5d)

    +
  • +
  • +

    feat: Created document definition for polls (133e7e7)

    +
  • +
+

Fix

+
    +
  • +

    fix: Added question field to question model (d913b20)

    +
  • +
  • +

    fix: Added missing values when creating Poll document

    +
  • +
+

Add public and policies fields when creating Poll document (d4d147d)

+

Refactor

+
    +
  • refactor: Updated route and action to get list of polls
  • +
+

Changed workspace route and action to use PollShort scheme to response to exclude list of questions and policies from the list (aa23e32)

+

Style

+
    +
  • style: Removed empty line at the beginning (cfad0ef)
  • +
+

v0.7.0 (2023-09-04)

+

Build

+
    +
  • +

    build: Added setuptools-scm package (7c2a914)

    +
  • +
  • +

    build: Updated the dependencies (0608158)

    +
  • +
  • +

    build: Deleted pytest.ini

    +
  • +
+

Deleted pytest.ini, the config was moved to pyproject.toml (88874c5)

+

Ci

+
    +
  • +

    ci: replaced semantic-release version from 8.0.x to 8.0.8 (329dafe)

    +
  • +
  • +

    ci: Added permisions to semantic-release action (ef15984)

    +
  • +
  • +

    ci: Changed tests action trigger

    +
  • +
+

Trigger tests action on pull requests into main branch (ebf3b66)

+
    +
  • +

    ci: Updated semantic_release config (0e92f50)

    +
  • +
  • +

    ci: Added tag_commit option (a6276b9)

    +
  • +
+

Feature

+
    +
  • +

    feat: Add coveralls action (48f6883)

    +
  • +
  • +

    feat: Added xml coverage report when testing (33a43e2)

    +
  • +
  • +

    feat: Added exception for error when removing a member (b14b2c1)

    +
  • +
  • +

    feat: Added schema for PATCH request to Update Workspace (0362849)

    +
  • +
  • +

    feat: Added query params to GET Group request

    +
  • +
+

Added query param include, to get policies and/or members of the groups, when calling GET Group request (ac5b739)

+
    +
  • feat: Added the enpoints to get all possible permissions
  • +
+

Created route endpoints and actions for getting Groups and Workspace +permissions list

+

Closes #50 (738f59b)

+
    +
  • feat: Included Group open_router
  • +
+

Added open_router from Group routes to the app (ac70686)

+
    +
  • feat: Added enpoint to get list of all accounts (e42a3e4)
  • +
+

Fix

+
    +
  • +

    fix: Fixed build command for semantic-release (1f14bab)

    +
  • +
  • +

    fix: Fixed repo name of semantic-release action (85fa9b1)

    +
  • +
  • +

    fix: Changed coverage file format to lcov (1f5a8bf)

    +
  • +
  • +

    fix: Added path to coverage file (bb2da33)

    +
  • +
  • +

    fix: Fixed issue with mypy

    +
  • +
+

Fixed issue with mypy not parsing BaseSettings type (d540f7f)

+
    +
  • +

    fix: Fixed issue with setuptools-scm (1a63883)

    +
  • +
  • +

    fix: [BUG]: Functions return hashed passwords #52 (89f98ef)

    +
  • +
  • +

    fix: Fixed issue with WorkspacePermissions (35b0e0a)

    +
  • +
  • +

    fix: Removed group field from Group Schema (873c048)

    +
  • +
  • +

    fix: Fixed bug when returning output of update policy (af13f6f)

    +
  • +
  • +

    fix: Fixed error when removing members (2a20596)

    +
  • +
+

Refactor

+
    +
  • +

    refactor: Deleted empty models directory (88913a0)

    +
  • +
  • +

    refactor: Moved documents.py from model to src (7244b4a)

    +
  • +
  • +

    refactor: Removed empty fields from response schema (bb893cd)

    +
  • +
  • +

    refactor: Changed description max length to 1000 (b82dbc2)

    +
  • +
  • +

    refactor: Changed few test according to default permissions (32d513e)

    +
  • +
  • +

    refactor: Tested Workspace and Group actions, minor fixes (eec6c74)

    +
  • +
  • +

    refactor: Renamed get_all_group_policies action

    +
  • +
+

Renamed get_all_group_policies action to get_group_policies (4dc2b3c)

+
    +
  • refactor: Renamed get_all_group_policies action
  • +
+

Renamed get_all_group_policies action to get_group_policies (4f65216)

+
    +
  • refactor: Renamed get_all_group_policies action
  • +
+

Renamed get_all_group_policies action to get_group_policies (8ff77f1)

+
    +
  • refactor: Moved action to get all permissions
  • +
+

Moved action to get all permissions to a separate action file, so +getting list of permissions does not require a permission (5d24b40)

+
    +
  • refactor: Changed default permissions for new policies (2436c4d)
  • +
+

Style

+
    +
  • +

    style: Code cleanup and reorganization (1c1ee52)

    +
  • +
  • +

    style: Ignore typing (d262c3b)

    +
  • +
  • +

    style: Cleanup, renamed few variables (3bdec3f)

    +
  • +
  • +

    style: Updated route description

    +
  • +
+

Expanded GET workspace request descriptions, renamed Workspace_resources to query_params (d381846)

+

Unknown

+
    +
  • Update README.md
  • +
+

Added coverage badge (8d85ad4)

+
    +
  • Merge pull request #54 from unipoll/development
  • +
+

Development (b134f05)

+
    +
  • +

    revert: Replaced file argument to path-to-lcov (a603c1d)

    +
  • +
  • +

    Merge pull request #49 from unipoll/front-end

    +
  • +
+

Updates for Front End (d45e8fc)

+

v0.6.1 (2023-06-30)

+

Fix

+
    +
  • fix: Fix no tag issue (d0120cd)
  • +
+

v0.6.0 (2023-06-30)

+

Ci

+
    +
  • +

    ci: Updated setup config and changelog (c3a74b3)

    +
  • +
  • +

    ci: Add upload to repository (aec6992)

    +
  • +
  • +

    ci: Added git installation before checkout (7f49834)

    +
  • +
+

v0.5.0 (2023-06-30)

+

Ci

+
    +
  • +

    ci: Updated release workflow (faeda92)

    +
  • +
  • +

    ci: Specified branch for semantic-release (f93c0e8)

    +
  • +
  • +

    ci: Added python-semantic-release (de1e39d)

    +
  • +
+

Unknown

+
    +
  • Merge pull request #48 from unipoll/Development
  • +
+

Development (c654a93)

+
    +
  • Merge pull request #47 from unipoll/Development
  • +
+

Changed workflows to be dispatched manually (6cc8a19)

+
    +
  • +

    Changed workflows to be dispatched manually (649bc63)

    +
  • +
  • +

    Merge pull request #46 from unipoll/Development

    +
  • +
+

Fixing Docker Buildx Issue (eade4f8)

+
    +
  • +

    Closes #45 (de2eec7)

    +
  • +
  • +

    Merge pull request #44 from unipoll/Development

    +
  • +
+

Config and verison update (108a6e0)

+
    +
  • +

    Updated version (15c32d3)

    +
  • +
  • +

    Merge pull request #42 from unipoll/Development

    +
  • +
+

v0.7.42 Update (1b3ffde)

+
    +
  • +

    Added admin email and Fields for settings (b413dc0)

    +
  • +
  • +

    Removed erroneous get_account_db() (81554fc)

    +
  • +
  • +

    Cleanup (3009f56)

    +
  • +
  • +

    Added workflow dispatch (24e11b5)

    +
  • +
  • +

    Changed release package to softprops/action-gh-release@v1 (86b1183)

    +
  • +
  • +

    Fixed the runner issue with release workflow (de79855)

    +
  • +
  • +

    Fixed issue with missing build module (52feb68)

    +
  • +
  • +

    Updated dependencies (bfb6a47)

    +
  • +
  • +

    Fixed Runner name (a162d81)

    +
  • +
  • +

    Merge remote-tracking branch 'origin/main' into Development (e498f11)

    +
  • +
  • +

    Changed runner (c502801)

    +
  • +
  • +

    Added workflow to deploy docker images on release (6aee500)

    +
  • +
  • +

    Created docker file (11618e3)

    +
  • +
  • +

    Fixed flake8 and mypy issues (77c6cd0)

    +
  • +
  • +

    Fixed spelling issues and print statements (1b8ff7b)

    +
  • +
  • +

    Changed secrete to use settings from config +Added Client ID to settings (f7a878e)

    +
  • +
  • +

    Specified typing (4aaac46)

    +
  • +
  • +

    Changed return to Group instead of GroupShort (9c30de8)

    +
  • +
  • +

    Moved access token model, update auth response (2f79bd7)

    +
  • +
  • +

    Added query params to get_workspace endpoint (9bfe492)

    +
  • +
  • +

    Added endpoint for postman to refresh tokens (c18219c)

    +
  • +
  • +

    Updated delete_account to remove access token (4e0685f)

    +
  • +
  • +

    Merge pull request #41 from unipoll/test_tox

    +
  • +
+

Fixed issues to pass tox testing (7b0a535)

+
    +
  • +

    Fixed mypy errors (a3dbb9c)

    +
  • +
  • +

    Removed check for untyped function definitions (bde8ee0)

    +
  • +
  • +

    Fixing typing errors from mypy (8f0f3d7)

    +
  • +
  • +

    Cleanup (f1accd4)

    +
  • +
  • +

    Dictionary (38f360f)

    +
  • +
  • +

    test workflow on commit (60b3bee)

    +
  • +
  • +

    renamed workflow (c88b0c3)

    +
  • +
  • +

    testing tox (2f985fc)

    +
  • +
  • +

    Debugging action runner (43e4a3a)

    +
  • +
  • +

    Remove python3.10 as it does not pass the tests (ebe0900)

    +
  • +
  • +

    Cleanup (b77224b)

    +
  • +
  • +

    flake8 (65e1169)

    +
  • +
  • +

    Changed load order (839a3db)

    +
  • +
  • +

    Fixed issue with accounts router (0e6477d)

    +
  • +
  • +

    renamed arc runner (54b531f)

    +
  • +
  • +

    Testing arc-runner-set (78ad1be)

    +
  • +
  • +

    Added app config and updated app version (5d51243)

    +
  • +
  • +

    Run tests on pull requests (dabd85c)

    +
  • +
  • +

    Merge pull request #39 from unipoll/authentication

    +
  • +
+

Authentication (3137530)

+
    +
  • Merge pull request #38 from unipoll/group_testing
  • +
+

Updated Group Tests (ae188c3)

+
    +
  • +

    Merge branch 'websockets' into authentication (060dfe7)

    +
  • +
  • +

    Separated the code into separate files (726a17d)

    +
  • +
  • +

    Added endpoint and logic to refresh token (60b26e4)

    +
  • +
  • +

    Added custom strategy for authentication (6d812b0)

    +
  • +
  • +

    Cleaned up imports (043c2e2)

    +
  • +
  • +

    Testing GH Actions (bce7e16)

    +
  • +
  • +

    Added cleanup (4992d86)

    +
  • +
  • +

    Fix issue with tox-gh-actions (b1c5cf2)

    +
  • +
  • +

    Add option to suppress pip warning about running as root (2431351)

    +
  • +
  • +

    Fixed issue with PyJWT version (021a0c2)

    +
  • +
  • +

    Updated tests action to use self-hosted runner (71cc8c8)

    +
  • +
  • +

    Added WS router (a8e7a70)

    +
  • +
  • +

    Added Login route to return correct OAuth body +Moved imported routers to the separate file (f446650)

    +
  • +
  • +

    Added the default WS endpoint with dependencies +Added dependencies to check if token or cookies were supplied (3482215)

    +
  • +
  • +

    Added WS manager (401ef6a)

    +
  • +
  • +

    Fixed all tests in group testing (0eb4437)

    +
  • +
  • +

    Fixed issue with fetching group links (f1a9f7b)

    +
  • +
  • +

    Fixed endpoint naming, +Added route to get all policies, +Added route to delete members (afbb4a1)

    +
  • +
  • +

    Added action to get all policies +Replaced action to set policy (699b203)

    +
  • +
  • +

    Cleaned files, stylistic (bd5e4e0)

    +
  • +
  • +

    Removed redundant print statements (e85c142)

    +
  • +
  • +

    Fixed status code (cf70e24)

    +
  • +
  • +

    Updated group testing (1d6cb74)

    +
  • +
  • +

    minor stylistic changes (316cad9)

    +
  • +
  • +

    Added tests to Get all Policies, Set Permissions, and Delete Workspace (5483388)

    +
  • +
  • +

    Removed deprecated code (17a08f5)

    +
  • +
  • +

    minor stylistic changes (5db228a)

    +
  • +
  • +

    Added dependency to get and return account (69bd3cd)

    +
  • +
  • +

    Updated route to delete current active user +Replaced default route to delete account by id (dada11f)

    +
  • +
  • +

    Renamed GET all_policies to GET policies (2512257)

    +
  • +
  • +

    minor changes (7acb080)

    +
  • +
  • +

    Python version changed (c66246a)

    +
  • +
  • +

    Minor changes (1204244)

    +
  • +
  • +

    Added optional field for specifying Account ID (b9812b6)

    +
  • +
  • +

    Added remove_member method to resources (c9ee950)

    +
  • +
  • +

    Changed Delete action to remove residual data (b52067a)

    +
  • +
  • +

    Fixed set_workspace_policy (e9f0ad4)

    +
  • +
  • +

    Merge branch 'workspace_testing' of github.com:mike-pisman/PollingAPI into workspace_testing (e38fcb4)

    +
  • +
  • +

    Added second workspace for testing +Added test to update workspace info with duplicate name +Added cleanup after tests (936d90b)

    +
  • +
  • +

    Fixed wrong error code on Not Found Exception (fb0a6a3)

    +
  • +
  • +

    Added policy deletion to delete workspace action (6946031)

    +
  • +
  • +

    Fixed status code for workspace deletion (fef2522)

    +
  • +
  • +

    Update README.md

    +
  • +
+

fixed link to wiki (e25ecde)

+
    +
  • Update README.md
  • +
+

fixed link to wiki (600f1b2)

+
    +
  • +

    Created workspace tests +Coverage: action 46%, routes 57%, exceptions 77% (1e3066e)

    +
  • +
  • +

    Created file to test permissions (57bb3ac)

    +
  • +
  • +

    removed requirements_dev (d1f6788)

    +
  • +
  • +

    Updated requirements (f645cf6)

    +
  • +
  • +

    Removed deprecated debug flag (87ff011)

    +
  • +
  • +

    Changed group tests order to run after workspace tests (d6f0b0a)

    +
  • +
  • +

    Update check_workspace_permission to check if user id superuser (73602a6)

    +
  • +
  • +

    Updated tests for Account(previously test_1_user) (2dfe1d7)

    +
  • +
  • +

    Updated version (a2add49)

    +
  • +
  • +

    Moved List of document models to mongo_db.py +Renamed get_user_db to get_account_db +Moved create_link function to models/documents.py (7d45916)

    +
  • +
  • +

    Added account router +Fixed naming for imported routers +Renamed user into account +Moved List of document models to mongo_db.py (27c144a)

    +
  • +
  • +

    Added database strategy for storing access tokens (81f467e)

    +
  • +
  • +

    Added recursive permission lookup through all nested groups +Added constants for default permission (9130d4e)

    +
  • +
  • +

    Added PolicyOutput, PolicyList schemas +Added optional permissions field to PolicyShort +Added optional field policy_id for PolicyInput (2732830)

    +
  • +
  • +

    Added Member, AddMembers, MemberList schemas +Created new member schemas in separate file schemas/members.py (8b6fd5a)

    +
  • +
  • +

    Removed deprecated member schemas (c5df2f0)

    +
  • +
  • +

    Removed deprecated member schemas +Removed regex filter for names (cd5600b)

    +
  • +
  • +

    Fixed missing last name (10d42c8)

    +
  • +
  • +

    Added delete_members, get_all_workspace_policies endpoints +Modified endpoints to return HTTP Exceptions in case of catching APIExceptions +Change updating method for workspace from PUT to PATCH (6f175d7)

    +
  • +
  • +

    Modified all endpoints to return HTTPException on error(APIException) (5e3bcb6)

    +
  • +
  • +

    Replaced old routed definition with new format +Removed GET {user_id}/groups (deprecated) +Modified delete_user to use action delete_user and follow general format (61afe4b)

    +
  • +
  • +

    Expanded name field to 50 characters +Added boolean Save option to add_member method +Fixed issue with wrong id type @65 (09b5e47)

    +
  • +
  • +

    Modified AddingExistingMember exception to use APIException class (89f3375)

    +
  • +
  • +

    Added PolicyNotFound exception +Created Policy Exception file exceptions/policy.py (6e8c776)

    +
  • +
  • +

    Removed deprecated UserNotInGroup, UserAlreadyExists +Reworked UserNotAuthorized, AddingExistingMember to use APIException (0898540)

    +
  • +
  • +

    Added ErrorWhileDeleting exception +Replaced deprecated AccountNotFound with Resource exception (3a41dc8)

    +
  • +
  • +

    Converted exceptions from HTTPException to custom class APIException (7711dd5)

    +
  • +
  • +

    hid init files, (35cd326)

    +
  • +
  • +

    Renamed get/add permission to get/add policy +Added action to get list of all workspace policies +Replaced default permissions with constants from Permissions.py +Added MemberList schemas for get/add members +Fixed get_workspace_members output schema (ba40661)

    +
  • +
  • +

    Removed deprecated dependency method (0552ccb)

    +
  • +
  • +

    Added account_id query to get/post_permission +Added MemberList Schemas to get/post_members (bf1b856)

    +
  • +
  • +

    Moved account_manager (127898b)

    +
  • +
  • +

    Remove settings.json from staging area (2dad989)

    +
  • +
  • +

    Added Permissions, finished Rework (3b5e736)

    +
  • +
  • +

    cleanup (57566b6)

    +
  • +
  • +

    Created dependency module (ae1ef10)

    +
  • +
  • +

    Renamed user into account (99b135a)

    +
  • +
  • +

    Moved all Document models into one file (ac39ca5)

    +
  • +
  • +

    Added policy and permission (untested) (9f2d06b)

    +
  • +
  • +

    Hid directories not related to project (8a6d8a1)

    +
  • +
  • +

    Added group router (d62a4d1)

    +
  • +
  • +

    Added basic CRUD and CR for members (6487115)

    +
  • +
  • +

    Added basic CRUD, CR for workspace members/groups (922278f)

    +
  • +
  • +

    Added ErrorWhileDeleting exception (1f90189)

    +
  • +
  • +

    Created actions to get/add members to workspace (13d6128)

    +
  • +
  • +

    Changed list_groups route to use get_user_groups() (a5615cb)

    +
  • +
  • +

    Fixed get_user_groups(); +Updated create_group() to add group to workspace (ba56021)

    +
  • +
  • +

    Added action to create groups (eb8d747)

    +
  • +
  • +

    Update import naming (3a77b93)

    +
  • +
  • +

    Renamed UserRead Schemas (96d30df)

    +
  • +
  • +

    Renamed and updated output schemas for groups (cd46a88)

    +
  • +
  • +

    Removed group list from user model (7de58d8)

    +
  • +
  • +

    Move route to list groups into workspace router (a1af1db)

    +
  • +
  • +

    Update group model to use links +Added method for adding user link (2bc7c78)

    +
  • +
  • +

    Added ids to workspace output schemas (bb525b7)

    +
  • +
  • +

    Added group actions to GET list of groups (154a26e)

    +
  • +
  • +

    Added a list of group links to Workspace model (b626226)

    +
  • +
  • +

    Created an abstract class for exceptions (e5eba2d)

    +
  • +
  • +

    Added Workspace router to the project +Added Workspace document model to the database +Added set_active_user Dependency to save user in the context +Temporary removed user and group routers from the project (a27d8f8)

    +
  • +
  • +

    Added a ContextVar for current user (bd6c1cc)

    +
  • +
  • +

    Added bson to the dictionary (b6fec56)

    +
  • +
  • +

    Added schema, route, and action to create a workspace (257ae4d)

    +
  • +
  • +

    Added exceptions for workspace creation (7399fe0)

    +
  • +
  • +

    Added GET route to list workspaces (2dbc221)

    +
  • +
  • +

    Created actions to get a list of workspaces (c768bb9)

    +
  • +
  • +

    Created schemas for reading workspaces (d34ce93)

    +
  • +
  • +

    Created WorkspaceID schema (bd4fa0c)

    +
  • +
  • +

    Created method to add member to the workspace list (2e299df)

    +
  • +
  • +

    Created Workspace model (81eb993)

    +
  • +
  • +

    Initial version of release workflow (e8fa47c)

    +
  • +
  • +

    Initial version of postman workflow (0334c4a)

    +
  • +
  • +

    Removed extra checkout step (0568fe8)

    +
  • +
  • +

    Added links (ea3a975)

    +
  • +
  • +

    Update (9a03d12)

    +
  • +
  • +

    Added 0.0.4 documentation (6e40ed2)

    +
  • +
  • +

    Added 0.0.5 version (8cd42fc)

    +
  • +
  • +

    Merge pull request #30 from mike-pisman/Testing

    +
  • +
+

Testing (e5ec36a)

+
    +
  • +

    Merge branch 'Development' into Testing (7815e67)

    +
  • +
  • +

    Fixed pyproject.toml (11b1e14)

    +
  • +
  • +

    removed redundant print statement (293ee4c)

    +
  • +
  • +

    Update test to delete user using endpoint /users/me (a3371ab)

    +
  • +
  • +

    Fixed mypy issues (96f9bbc)

    +
  • +
  • +

    Added dynamic version setup through config file (3db2b8f)

    +
  • +
  • +

    Removed trailing space (3fc468b)

    +
  • +
  • +

    Merge pull request #29 from mike-pisman/Groups

    +
  • +
+

Groups (43a551a)

+
    +
  • +

    Added comments (92ba323)

    +
  • +
  • +

    Styling (47f3032)

    +
  • +
  • +

    Replaced PydanticObjectId with UserID (d9b776d)

    +
  • +
  • +

    Styling (13c509f)

    +
  • +
  • +

    Added type check (e19cbc9)

    +
  • +
  • +

    Fixed error with updating the role (tested) (1cf764d)

    +
  • +
  • +

    Replaced PydanticObjectID with UserID/GroupID (50523ca)

    +
  • +
  • +

    Added comments (bd32441)

    +
  • +
  • +

    Added scheme to update member (b5703c3)

    +
  • +
  • +

    Added route to get member info and update member's role (1ec93ec)

    +
  • +
  • +

    Added route to get personal group, cleaned files (431547e)

    +
  • +
  • +

    Merge pull request #28 from mike-pisman/Accounts

    +
  • +
+

Added delete /users/me route (1ed7fcf)

+
    +
  • +

    Merge branch 'Testing' into Accounts (b8c5674)

    +
  • +
  • +

    Added delete /users/me route (7ed1f69)

    +
  • +
  • +

    Fixed mypy error (d377361)

    +
  • +
  • +

    Changed FIXME to BUG (eaa61e9)

    +
  • +
  • +

    Added pydantic plugin for mypy (2bc21d2)

    +
  • +
  • +

    Changed tests to run only on pull into Development (651adc7)

    +
  • +
  • +

    Added the badge for tests (d38d3fc)

    +
  • +
  • +

    Fixed issue with muliple directories when building (b436733)

    +
  • +
  • +

    Merge pull request #26 from mike-pisman/Testing

    +
  • +
+

Updates and Github actions (2d07a9a)

+
    +
  • +

    Cleaned up files, fixed issues with UserID (b5b454f)

    +
  • +
  • +

    Merge pull request #25 from mike-pisman:Groups

    +
  • +
+

Merge pull request #24 from mike-pisman:Accounts (3a9f88c)

+
    +
  • Merge pull request #24 from mike-pisman:Accounts
  • +
+

Removed testing on pull, test only on push (d1fc772)

+
    +
  • +

    Replaced PydanticObjectId for GroupID (b6acbeb)

    +
  • +
  • +

    Replaced PydanticObjectId with UserID (b1ef77f)

    +
  • +
  • +

    Removed testing on pull, test only on push (30770ce)

    +
  • +
  • +

    Updated node versions (08de6d0)

    +
  • +
  • +

    Removed database test, updated Github workflow (b6b3bb5)

    +
  • +
  • +

    Removed redundant .env creation (9c76543)

    +
  • +
  • +

    Added MONGODB_URL to tox (e35b78b)

    +
  • +
  • +

    Added test to check database connection (26dad87)

    +
  • +
  • +

    Added Postman integration (71df669)

    +
  • +
  • +

    Fixed incorrect fastapi-users import (66b7841)

    +
  • +
  • +

    Added debug for .env to check what's causing a failure (dc1ee52)

    +
  • +
  • +

    Fixed .env (37d9a0a)

    +
  • +
  • +

    Added MongoDB connection url as .env file entry (3fac4cb)

    +
  • +
  • +

    Added the comma that was causing the test failure +Removed py39, as it is too old (132e477)

    +
  • +
  • +

    Changed python version to string(yaml specifics) (8172690)

    +
  • +
  • +

    Changed the action to run on push (f5924fd)

    +
  • +
  • +

    Merge pull request #23 from mike-pisman/Testing

    +
  • +
+

Pulling changes to Development version 0.0.5 (1762bbf)

+
    +
  • +

    Created Tests GitHub action (41c64ee)

    +
  • +
  • +

    Cleaned the files (277d3c5)

    +
  • +
  • +

    removed git -e entry that was casing an error (18edca4)

    +
  • +
  • +

    Fixed issue with author format (72cf89d)

    +
  • +
  • +

    setup.py is no longer needed (3df063d)

    +
  • +
  • +

    Added basic tox and setuptools configuration (49b9053)

    +
  • +
  • +

    Cleaned the file for mypy and flake8 (24261f2)

    +
  • +
  • +

    Added requirements_dev.txt for development/testing (13eb628)

    +
  • +
  • +

    Changed imports to avoid styling issues (3279770)

    +
  • +
  • +

    Added pytest-cov plugin (2b987f4)

    +
  • +
  • +

    Moved tests outside of the app directory +Added response types +Changed print statement to use colored_debug +Added test_delete_group_no_owner() +Cleaned the files for mypy and flake8 (9c39fc1)

    +
  • +
  • +

    removed trailing space (359bd01)

    +
  • +
  • +

    Added response types and cleaned the files for mypy and flake8 (2d62228)

    +
  • +
  • +

    Fixed import issue, cleaned the file (a0fb46d)

    +
  • +
  • +

    Merge pull request #22 from mike-pisman:Groups

    +
  • +
+

No changes need review, update Groups and Users. (c54d543)

+
    +
  • +

    Updated response models, cleaned files for mypy and flake8 (1a72a4d)

    +
  • +
  • +

    Added settings.json to repo (56871e9)

    +
  • +
  • +

    Merge pull request #21 from mike-pisman/Accounts

    +
  • +
+

Add Account's updates to Groups (1144158)

+
    +
  • +

    Merge branch 'Groups' into Accounts (d297e13)

    +
  • +
  • +

    Accepted incoming changes (f1302b1)

    +
  • +
  • +

    Added .history folder (f95c1d9)

    +
  • +
  • +

    Changed the response of list_user_groups(), cleaned the file (660de6b)

    +
  • +
  • +

    Replaced print with colored print, cleaned the file (01c0569)

    +
  • +
  • +

    Cleaned files for mypy and flake8 (f71ec1a)

    +
  • +
  • +

    Changed email field from str to EmailStr (db84108)

    +
  • +
  • +

    Improved group testing:

    +
  • +
  • Added tests during group creation
  • +
  • Added testing for group deletion
  • +
  • +

    Added debug message for various actions (d4419e5)

    +
  • +
  • +

    Merge pull request #20 from mike-pisman:Groups

    +
  • +
+

Fixed unit test to Add members to test group (0d2e272)

+
    +
  • +

    Made member routes to exclusive +Updated routes to use new schemas for members (737cc5c)

    +
  • +
  • +

    Update creation event to use colored debug (09fdf88)

    +
  • +
  • +

    Updated Group schemas:

    +
  • +
  • Added GroupReadSimple
  • +
  • Added GroupReadFull
  • +
  • Added GroupMember schema
  • +
  • Updated GroupReadMembers
  • +
  • +

    Added examples (1723b33)

    +
  • +
  • +

    Fixed unit test to Add members to test group (08a1e78)

    +
  • +
  • +

    Merge pull request #19 from mike-pisman:Groups

    +
  • +
+

Update Group rouing and functionality (64b7003)

+
    +
  • +

    Changed print to colored debug (c5e3f70)

    +
  • +
  • +

    Added GET users request, changed tags (991b140)

    +
  • +
  • +

    Merge pull request #18 from mike-pisman/Groups

    +
  • +
+

Groups (df823a2)

+
    +
  • Merge pull request #17 from mike-pisman/Groups
  • +
+

Groups (7fde29b)

+
    +
  • +

    Merge branch 'Development' into Groups (7dd3577)

    +
  • +
  • +

    Merge pull request #16 from mike-pisman/Testing

    +
  • +
+

Testing (b02391b)

+
    +
  • +

    Updated .gitignore (d748ffa)

    +
  • +
  • +

    Updated create_group (5110a59)

    +
  • +
  • +

    Updated group_test (55445b5)

    +
  • +
  • +

    Removed the work in progress (c1937c9)

    +
  • +
  • +

    Merge pull request #15 from mike-pisman/Groups

    +
  • +
+

Fixed bug with User.update (644dfd1)

+
    +
  • +

    Fixed bug with User.update (607c8a0)

    +
  • +
  • +

    Updated Group test (470711d)

    +
  • +
  • +

    Updated .gitignore (a230cb5)

    +
  • +
  • +

    Started working on group tests (63707cb)

    +
  • +
  • +

    Added tests for user (5af074d)

    +
  • +
  • +

    Added testing module (92332ca)

    +
  • +
  • +

    Updated new group schemas (ae4a403)

    +
  • +
  • +

    Added util function file for users (57e6a9c)

    +
  • +
  • +

    Added new schemas: UserReadBasicInfo, UserAddToGroup +Added examples to schemas (4458112)

    +
  • +
  • +

    Major rework of group routes (ca08f25)

    +
  • +
  • +

    Defined after_event to watch for updates (05cb5b1)

    +
  • +
  • +

    Updated UserNotFound to print different messages (70c821a)

    +
  • +
  • +

    Added UserNotInGroup, updated status codes (117f76c)

    +
  • +
  • +

    Added reloading to uvicorn (d86460b)

    +
  • +
  • +

    Moved main to outer folder (5cf3b5f)

    +
  • +
  • +

    Added Settings model for using with .env (c22fd15)

    +
  • +
  • +

    Fixed tag spelling for login (239e153)

    +
  • +
  • +

    Changed api version (28810b8)

    +
  • +
  • +

    Updated Group schemas +Added config for examples and fields for validation (d1f0aa5)

    +
  • +
  • +

    Improved group routes, work in progress

    +
  • +
  • GET "/group?query" with query works
  • +
  • +

    POST "/group" to create a group works (1960ffa)

    +
  • +
  • +

    Cleaned Group model +Added field and basic validation (423acd7)

    +
  • +
  • +

    Updated names of exceptions, Added GroupNotFound (dc454e4)

    +
  • +
  • +

    Add test_venv to .gitignore (a92784d)

    +
  • +
  • +

    Added get_user_groups() util function (b1e01ef)

    +
  • +
  • +

    Added GroupList, GroupRead, GroupCreate schemas (f842ff1)

    +
  • +
  • +

    Added get /users/groups route (975fce1)

    +
  • +
  • +

    Added first_name, last_name fields to User model (4b6d000)

    +
  • +
  • +

    Updated User schema to store first_name, last_name (b179755)

    +
  • +
  • +

    Imported routes for cleaner set up (dcbef08)

    +
  • +
  • +

    Added UserNotFound exception (298ceac)

    +
  • +
  • +

    Added classes for http exceptions (0ee1799)

    +
  • +
  • +

    Renamed Exceptions folder (27628d7)

    +
  • +
  • +

    Renamed tags (d40fed6)

    +
  • +
  • +

    Added functions to print colored messages (d6625d7)

    +
  • +
  • +

    Created utlls folder (70b4ac4)

    +
  • +
  • +

    Added colorama (ad929c7)

    +
  • +
  • +

    Fixed missing type (f23a5f5)

    +
  • +
  • +

    Improved Group retrieval for /grou GET (92765b5)

    +
  • +
  • +

    Merge pull request #8 from mike-pisman/Accounts

    +
  • +
+

Pulling changes from Accounts for Postman integration (eb1782f)

+
    +
  • +

    Added add_user() to Group model (158db53)

    +
  • +
  • +

    Started add_user_to_group() (8171447)

    +
  • +
  • +

    Temporarely changed groups type from Dict to List (f77b0aa)

    +
  • +
  • +

    Added defenition for user deletion method (5cf2d32)

    +
  • +
  • +

    Created folder for storing custom exceptions (cb9b0bb)

    +
  • +
  • +

    Added init to schemas (225776d)

    +
  • +
  • +

    Added a group exception user_exists (84a8f9e)

    +
  • +
  • +

    Reworked group routes:

    +
  • +
  • added /post to create a new group
  • +
  • +

    Added /get to get all groups user belongs to (9d94e7e)

    +
  • +
  • +

    changed owner from User to PydanticObjectId (e99de90)

    +
  • +
  • +

    Renamed Database (978a9ad)

    +
  • +
  • +

    Fixed bug "no Group class" (168943c)

    +
  • +
  • +

    Added group router (a301671)

    +
  • +
  • +

    Added requirements.txt (c0dca11)

    +
  • +
  • +

    Cleaned up files (97dd184)

    +
  • +
  • +

    Added Group model and started working on routes (4558f0d)

    +
  • +
  • +

    Added routes for users (3b68fcb)

    +
  • +
  • +

    Added init.py files to create modules (a7f4f5a)

    +
  • +
  • +

    Organized project using modules (6677b10)

    +
  • +
  • +

    Created a separate main to run uvicorn (7c5b486)

    +
  • +
  • +

    Moved application definitions to app.py (67d018c)

    +
  • +
  • +

    Basic main (d922477)

    +
  • +
  • +

    Basic MongoDB (b7795cf)

    +
  • +
  • +

    Initial commit (becb151)

    +
  • +
+ + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/api-docs/assets/postman-auth.png b/api-docs/assets/postman-auth.png new file mode 100644 index 0000000000000000000000000000000000000000..d11200a7e90bfbb3501938f6e653eb013b5cdfa3 GIT binary patch literal 124259 zcmd432{hGh*f*+DNz)D?nTe7pWF8`!r;sTj2_f@5R!9;;l1vF9a}q)ll8^_g4{ zp6jac<-8K*%;h#Ix)esIuzlNh#aj=hJ3FbaO_TOKp^fSEHKwn$wM%4IQ-Ls)&z=X1e>RfGUl$9B35k^r#CDZl zVHFmp-G&Q#e`dkf0$)j13j9s>;A;s<6$QT7Z@YtQBpKXJs*Er1calBEms@)Y+{7o* zFzXTD6VJJPQhYJI_5alq&sFvuAt6!O=3n)!#gctblOc&sY?FCZz1eA6b2bNDaxcFg zH+867Sx+g+p#1#}p#(Ld#o%W5`y{uzZmmCZ6Qd#7=xnhR*yVp_q+TYUbg-W!g5s9q z(@_7Nc=yY@O4RneXK(sgwLORl@AH3M3;xBni1sYqpu2a~3^&95Hb%bXT;_j8T*E=z z*jSUUfdO>_smyU-K;TKAx%sKRo%H0oD>Xo_XD6osVPIvzJ zaa`s&3(M^)6K!qnLAUeg&r3*1OifM-)2r#}>3MmH#Wfu`a6pGET2)omyzofgNAtpz zl$5^S-nF&0?(S}G>V^kq#5?ySv8%#g9Zzv|bkx<=H8y6F`SEUj_F7@r=;-Ls(9lWU zTpLTvd-w0lkVUX}_4aN|q$e40Q`_17lxOmJ)G%r#Kqn+r{N~LY39sK84pbzA6pE4C zZ@;$`2n!8W^$w{r!IFyq=Jybw3sp~x@7_r=F)(pL&v)wzksEDEo2eSd#~Nb`J(niGe>Zz+M^0kTgEisjkE$MG4p>`X4`-67<8~1tB1hwVgJ$7REEgs?5(=B6CQ%0m2M-SqETL(EVX5P2oZY+I4s7;$Px`v@J94iaWnc(>@IaPq zNbP&{N!<*$hK7c^k01B#IN9H&?dqBhJE>hBc`}fz6F8uoCESg|jpeG|EV}3S@ zWW%g6K}-niSy{O?l~*b0GWjSjuIKLlqvGP?8Hb;zq=d?`h19+hV{85xc}&^#+BMG7 z36I6G3l}aVh`LxU&-O7eFs!bwCMG6+J4qJ!0gtMxsz2+?y4u?8$Bs3{@>?hk9Jp0x z>FS?WYnqvr6{VCmJ3D*v;zja6ytu!oZc57_ja3mHOO0uPy%RR#u|Jn}bz_v$p0=xO zpKCjp-d6bPm8X~2^3MTdY!)4zH+BP(q6w0A{o>_!^tgX7EuA`bs(r%w%$YM^cX#Am zF1Bo8-4NyHUo5C&JWqDBGyk?+3f{G9oZv-kyo_CE{?NG8mWPhccb&(g;(@Jo zP-^2GAs{9uW{Ld7i4&yK^b(%G)|RF?)f2UkQ)Omm7G69+(s)ot+jPy zW8>Y{rq@(4zM0#bsePY7hx^9Ba5h$@udmPR_p~(GA=0YxMNT8PZ6qq+$H(i;_@<_& zG7FlpL|CwA&zLuOXF0xgbnFfM@adBRbx0u7m%)*d^Ac&do5$BzR+s~x#>M^l^Cu`M zDDLUg3{^7=i{hf9ox67N=;fQ(+vlgH1$s^eG5J0-3JMI==YHJZZ!|THw{t__X>u~l z#?PiWAxcWh3Fo&BEhckJtfx=go0*xpyLXzGY8>$R*p_iWo2bIZ8hw1VX3L?!LrZWtqwAX3J43|BZzwbLe1jj z3}RRGud>HGYKY+-xUI6?KCimt?27lhB^ft2xANYO4qa~QWo#v*@+WHPcmvn2SzBAD zzuqI>=ucS_+<7l7jE9TsWoBj-Pw*kvt1=MZl1>@0Bn_@}0({Y=-j zzdJcO#kuanm7-keYiT)ctjq_u8SdV->yE#_gt+*eLUv_krDmo;tV&xy{mMi^SPU5p z{RxMIleuwyiO0h0E~BpFHw@87?3_wMwxv;w_s++;54 z3ZtJhGYkZRi3D%+A^H>Y^73VG-{QRyWOnS>;p5|@9K$o}Sh}^=QOR}kBz6(`-o3nr zCCo7mxb}B{e)s5ek=y@#KAfg;d}Cf#NuZ~L`vU8sP&sQ`+sz*-;n*CRqgF+43kxZi zg}0ILrw`@}-_L1rWFjIptCrnV9xKr?e= zZ7L7N9pyIe(If3kmoDk+i|oBlGV5{d*fAFu7pa#D!35Uqqmd-Hm`?G;h^0lRi;ACD z4J(pMK?CpBwp+dy%C2~aIb%qNE|h~n_SI^s=H|B3{^lEwD+x~qcaW4+zi@bwf3!k{ zqwS`V&g)oL6TVm~^4b}8viDcEH5dNB1~Ts}wk5vb@h@DcqPXR?L%fOnKS2rqDw25$ zk{JAT8}Xq-wy6i+OPo({J43sVE>tkq!hG9Y(nlM?X3bPtAgq$&_f9R_N=`oWA!5n@ z{{b?F;d%GsB(k_Bj`}1SmS%+;y=}gHWfUZ*_X|WQIIm}NUwP}iG}#`zRhgfkk0SN; z@8j{~$2|l0m02V1$)z0Gw=3Xbaq%)+xH!7AWJPL;;cOU#7|PmiZ1Z2zyZnbnN7Hn& z<|{83+b+$`Sz24i83|5vadT6J)LyxAC91J{CL}o60|!M}S$Y4i>fbXxc}5j4TP$_* zjGD{~*VopvI}Gzpr1kVVm!>)_tlHG(+{Mv`=jZ3UdIE}zi;ePx;+ibqmbJcR)Vv^c z(j#GKTb2U;*v!Plk)ucBTGMC02M^2FwhY-^S>C+1cU=CuxxweOw6rAOHQ*)R?%rN> z@CU|BQoi)W-a4z7o|>P3`plU_l`q;RWRmT>711X8%G>~?)Rz1yg3THppZZ#9?7KR; zx;UPmu)nOtkSC}*)|=7R*xGt(wy$hn-{?41tEE7|!??JkA+=AR2w|7|$GNhiSFA3K z7QPMUOmzRy)<#*G*q{44H%Pms@8k>J2-5A_64a6=|Lf&`cInP-AwDh!JXA_+op7$G zs1Q7PPxkqbAC@UCdb+yuMcImx5ANNYTUel@rM0|qqdaNceho6UX7`PipsuFIc0VApOcf5v$JE1s~k~#Xbvp-945b@r3Hj9Lk95Z zC>)QA{qf@mZfke9L4}c20lmApk&O+ve^o|SR-us^K^E;%mKDI^hLu(8)Dq>QNil6s zU{FwaXy{PI*y!kC0zpGxKX^b%P0iNMPAFDI%gV#u-Myv;h5G5*n&(s^6OU_=LEk_B zm@HeXach(?*5&xnXaoMlCsnI~9TKQuMv zBqvKJYv3Z>y}aCRdrFDw_^igwj+Q$_1^xOn8D=VvvW7u4H6ciMoN#hnTjyLCJXM=ID zE86y#>+{4|3p@p(SXo)YZJ+#gySA>*uKV>3Z|``yl*3e18SRq*Yr(RPTYr|dZf-O- zs$^<+x3*FoIWqC{r(J=b3WwI^%W-98>+vE^+qZ8AV@XdRe|5b9OLMnb9=)@vxtZz6 zk$FIt~u4=$&yc9eiIN7Kt{S9yP>6};CjR3w{Jy@3=$qb92_6#q#_TLxoTy_ z4XJpLP$+~v!8ZZgakt&Clsp)WUsna!6Q?z6Jd+bYswGUk_J4L;gy2J$nsbVBL zvB_y#5Jj9xd~^AY&7S@H8IB&UzJB@QMIhsw3&hRdrmm!PKP)UaFHfFqbZm@A|JC=; z(I*XZbin!g%U9QbR?>vjYR8U$|4!tcrbp=LULBE)Y#5c4l&r6>H^>oWW@bj^eD}^M zy=~~x;=+QQy!?*s+aL2>K@of~lC;zjub1jxImmFEKu%8nxuN0YsZ-JQX35FP;*9Dk zEx&&M2BYLGYabX$Y8dtO@HnOaN|u{?#NeWa#xsrMDETwgY>JU!V4Itpz^S|ZlM4%@ zx}!@b#`N*ARw0><4g0nPl1{M`Bej;Jlz& zTrcbr)(6C;Hy9on!A;1}%v|yIm6N+$R_1l{W{&Fg)@rj~SYge`Jfq)+0|-d9p0xC~ zpz2aET5WYIpylxU_sRF{0SxHs>Y@k^Am^e@YW7+}%qmD+k6N1jK;X96qTtC>Wn&>hS2id=P)pVQ^2aW!rIXa`VrPzqk`9 z$w;9~FfDmXNE4dH7gcbFfu#%#=n~WhimYk+N3mxV6%|jMI#sm!tjeUb(oZVa1MqQT zV#2j2M-Tr?L*pN49K1&5_hRz(vZFZFhr_r6ndR3T8Ie6t@g^Jrp+fA#g9S za;bF(&ql=Cw{LNZx>7g#+y;hdP{eNEzAYclc!8|N^0ijF+K~0d>({RnL3{+8JZK}J zDS?sEce?XToGc$7--`F9@z$EIf7Llc4G=t^{MIku9#wB+V^eNFbf?~om29|lJaO;-{WsCv>iru`Aue>6 zd+;kpnirympdNo3UBFEM0W_}k^?6CNGfi{iOM=*Z?AwwO_xi|V#y(5Y;o<6@o@-@4 z--UR|?A*B%{BM2vXYuBsW8{aYjt61sj2Z&e*G_QMkFSF8Fd6&zGCQtGR{On(faM%3vDj9neM>z%+iG5 z;9&Qy?$fa0&XrAsY+)mouoR*VE&Tw7@1 zjf;yrBy;G{q1xKo6{^Nj$I8{QqlP^~Hk}XSn!KckUcy9{h?n@7;+dPpeP( zIV7fcE5m!~cVYLP@6=EdPVEy>A7#0zX}IsNG(}14nzH@V}J(EuBx>UpMilv#t9bO zUNC*(Oo$0kNYGgC-6Jb9kZ^EQFH*=+bu11G3)7t1cktlI^CxC!H0Lgnq_o^4@WnNG zEzj1neWc+v`a0o^`vn!j*Vk9=r8Qm;6jm{kRJ!Kl$6=n7A^=h=XP^XZ%i&SY%ty7R z`rOop57-qQh3UPoE2p>Vceomc#8Z{&WTmOqL~-B76%YZ$qokyPxjB14xTGYeP`MPf z<+Eqcx_Svhcr5wQFuL&S6Cs;QnwPTt<) zGN0Pov{)ks3n)3|pDUv->+9>Ip?FJH=H?z~-YmS#9p?DsyS;1a#6-e{DwR@73FWEz zW8PIHEHy*+C5E|6m!^U{TJdjwKPVv}DcRrC6LLA?OCGhoFugd}y-aPcNpCYBM_^sS zO7&-L69RNio^q`1?NCLI3fd6JNO7V5{{CFix)0Omdm# znzHiVP1kSoM=sf_-S2yA!>P3$8%ix5)k-TU8e&bRHvIwl938DpXx?S#4?(Cqsgn&> zi#<^n&IHW0fA3z9V?e;K7U`bPpM5KaavO5pG!e26HLp?QkUa$j1yGyA8Br06E26#| z?%0W~zAQIYtBxZnCzjgQ0*anERSMPq@|)stLbZ&!>&Nkl!Y zi(10@aoF*X$?4Oy`|dE$o%uL2Z_nls35fvsB-8I0MR1Fyvq+Oq`^!uC!M7+D8XiME zs4wz%0PIFaiHlS~P_nGao3&AUIijvY(bvfWW0_Z=Bkm(gCJLvq#xrqEek;{Xa}#`A zTvo$%42M%fU%Yq$L;#k9J(;5;cKUR_N!9i=&EVaK(`(kOHM<~}lLy|RvoCD87(o{* z#}O55e7X7cE5VAs`>HQ!bGoLLB$Mn;(}K%kEqu4u2S$Y7qFRje%Q&RVr?*|w)m68l zJWfUK=jZpbZen~q$oP1)QY5?7`ZRys-DlcdMP4eF$9wHCK zv0wJWg-yF=0{*VAuR~@1`0?XcD;JQxJ3IFRaW?Gv$fHiB2Fbe@ElE^Vl!qsbPQ}%k z-9VTB*H72r{e@kIxE}@vpG{7~SSU8By2BT*R>ha3|Vi>o&SijmM8(9Up0GW8aWI4S zreTF=ds`d-@#ADni#a(tC#NuKho^6~jv$BAzMuvwu!m3yUl<=!jQ7GRiXJWv^ z4<8cBy;1qn(=EDQU3WhZwHi>~sWmXctU&z*D@y>BRzTnTJtt9gdEc!(*W+fSrTsB8 z1Ioau7|CA0vEeQMX9fFmdfGlgKQth2@ZeEs=*}k?+MzDR+bBa1f|EarhPyXd)n_lywTPI4bB^uz%w56*{ z{qDSmyRCc@q;_NY2oE6|E7R~TGg z3Hxnsz<)6E`?Dm}?_S;F+HSS<&S(98NC+g)Bm3k~brSPOYOqP&#rt{vR+Tq?e){z3 zvR#GCa7}RNQ6UZvj!5yub~ft@R?Lz zWy5(YJ8S)|{8y{8T*^H9?^m;tg@pwOLkwcBI0m`7Jd@qws*KarDf?4eI{W*-z^K@I zR#bFWNXX5zilQ#^`E%A?{ud#^4t>}e@X#Qqzs$|f!D0UX;gbrH(^FIH(}m48l0PyO zUo?>23 zPK*9>4>Sjqv-g#jGGq+G_Jg-~Gp;0Utuj>@<#kL!EB|hm@5xs?n@VcK)jH9ZzIX3l zWA~xJ`FRJ?1mCg7BfXqr_Ji-=x=a~)j2;g72fvYd(p3=N1a62!K1eT|1X(hXr|&N~ zcs#eyO-{ZFI}K8l_6ZSD3cKDC+}+JjY~joSUlJv(-74c@96@~pP_+>(D=aKbO(pfa zURFDNFQvNcZr@vr5y8E?RrVaBr}w52QjcU$Y6e0G3p)bIZFW{tT->J3@EF-0aDhKm zaZRosM{Y5bNhamBP1ufa^0F&}<$62DKe<`hW#bdO4c*0C(l||1^~Mj{5y#SfyRHrA zEt77Ch55w&aFgi4u=@_b$w==6*D4bN;3A*{IMW>EyztqyAVb;h8y2$4wp01p* z`w{Glu$|6GIg6qJ_nGSs`v{;W#%AS&i!Uf>X;CIV7deEcplOtEavQq(k|p41TH6G= zPE^;!2GcqYtq6h)>OtK|XjmBJV0osbLpW|>r)eK-t>tZD$QcH2&tB>&3IGhBrM?RloD>Rwmip0eR`}-Md692*ts5#1ljaFH*U= zHkFvj7%Z!4Xz2ZWT3`O^VPOh7x~ET`94C;u{_OWDUfe$G;dYaj`qq}-%G*KCB=6yj z-QFV~Lm`848@z^Ul%f3+a>n`8c&)-hLgE|gt68-G zVbb2?<>=z-w{Z7A;U7jFXCzx)>EJkkm)l7tq^70<{A+Dt>x_r9xy&~3RywbqzFL-T zt){40uWRgc_TQJX{5G?8127D15qA{~)LE24s#yYjP*n73^$_gUi`G!iIy*aolMA~V zO-@6)!7T!QFf=r@v*R_Y8yGN#vcMTErc~F|bPAQw-Rh5-NGTy9PI{Nu-t*p2oJa{lrMq0umh?y*YTe1dhqxl8=rAT&Y1~M`qAS2IL zqK@v_vj@7RYjIcyOJk zPjofCJiB2w4QwqKrz&wpohK%WT|_|O(bK2*nFw}&j6Hp9^T%c(W=^emyXeIC8zen$kP>>}A{MC0wL`0z4ffk|O3(%=%YK!t7 ziDO`iRsw=I$oajz46Pwje*$m0Oo;OveSuyhAljGA$#EQe0fB&|pg`*~%}f11|~=xfJr$zaS;*ttLJ58 z&}olR)c;u?P+!^uP?4s21INQ2+tkwXI1kU4fdM~f=dUKG z^`t60?xvW;g3!jq2#Jc)5eWIt6RpsDa&#I@PQS6~!kH5l6r^Tkltep&h5~U2kpid! zVB%5rUweCr|B1W-+PQz#!-RxW5egiVf*ugkp(&zs3((~}dv>dC1P(f29yHKqfJ~{A z!hC#=|B6D@L)m%-GHIGa=Zc{8;bm^010sdyF>T&%?q<{TCbY>M;RnMn!cvZ)e* zA|m=(?GS>$kBz}{9to1=x$;&3oj+&}DiX+Uw9=?$rL3GB1h327)VRiP-vnb-?QpVk zbJcQm*aGltXpF!k*l$>l@VYij0i0C0S)818piH%AhZ#Z+v^#KtdEL0ZmNl2C-9`TZ;iD~Go@Dh?dgxmDb#IGx5u17-U zBH4>=x}Ya(8W=o{h`1_1C$%wmzOW1NiX_j;Oz z!Qu3COk%Fw$BvC|tS+_*A6Z>l0sgE6Mko=xtfBERCZ^bL%a9{;s^lWb_Wl~p2NJtE~J`rKT{={DSS+U$-?b92$mj-&5BOJ@H`&qEYk01Xr z*`5Vn{@SCV{spI%r6nO)7U!`pj3I^EsKRpz3K>~4E(}}5sKma?qrP*REE|CC%^T{! z`jz)W{f^xSm;>l%ROQcdva$I$k8dsI`N1q9l@?$4#D)_-;JbcG=3c|7?_!fsNqy1P z>bsD^DLK_T|AgT$l}K=*{;;;dkA3;_CH-M;q@Jul-hq*p_T_9uLx3>C=Mub zE47evWLYENr3D4;Ml&8$G^+IN6WuvE0Mj6(_5+d`2R>>}4d$Na34&xR9;C$)1)+0N z#S@q~R1S_&D;y8PTi2PVi`fQKcjq%F)S5g#L?wQY%(EcfrM$*GH6!U zuODNKc%#P+AtN?6R#I$1O}bs$&24#b@R?E?E7|tETjv=9-`ZP3exTl4^t8`~epEU~=Q7O*bi$C@=aDXn zm#k6R4@&&{2OSA!fuCRHQe94xV75+{!y20T+mLW$^`GOEYJw7q-;M z;51)Pzly53K@(JcF;n|%C0F!)F3PDZ6AOEXVV#S*&kfc*-cK@^c=}pZ>r>54dU|?s zpS9Ob3s8Kf1WRODt9bYA+TmZtOm^q#x!ZAzVXe|+McA6JUlT|REL)!A;nwdlF36v) zaeR(8vk3j@Nz<6r#?Zl)2lR&zyNF$OP)pVz3zUJ(&C43ejs|{1qPo^YC+C!5N&br$ zyOwYNW%`Uu)R)G{Sj1y?vj~WbtGEozi^`=q*w{P(wMi}naaUZR$3~eUh|P% z`6Cf>D=2(2h9J!KMAgNPi;8?|_=DE-7mu9G4xiZCT(0Eg5FlgrXXsTbsQNJlDE?j#Qn4>z|g8I+euc84uC=uB&0 zMMeiJ3%J>1%}LFpj_3?JI@Cpmc^zIJ9#D%o6Ur4IKWOS`Y;N8{ z>oQAXK-30wS$#u_{XP z+Z5@at&ida%K_y?49N#Z3XTez1*$;YbdFvDY@EX@MO`+&qtUv^Y4lfkp~C8B>q$qN zLEf`S^0`ak;^jTKcW)0~6&b_HNk_hVS2=o6tE$~h-gs7{d7(^lXPMj2nlp0p`bDn) ziJAtd@4WbL=H>qV`?UMyR8{vUDy8UTAwr~UXc!+C2LOS$h{kcB{wGbqKadrmkk27~ zQaS(e=(iYlhMQ|E^CJ)(y;etKpm>AuLxh}LfTsaN6nNF8IZ?uW?CWdgk8}s-&{bbN zp6)Ge`@86WiR6E<;LG0svS8t^jL_hS1(Yte-2Ck%zK!<=2M6_)p0X=~ShZN%jJZKG zgTn@&6I$bwCr=O?*fQ23+um%QU?z$pY$$DwWpFO!fgR$x=X5YNYxv z-^$k)_Hq|zRE+#GzDMjcS0KA05UghAv|27gJE93+*4B=xMKzE2T(NblWDe-GdDHay zi;(L6v~K8yyZoz0Yb)y?Jx~t&{lcZG0Err8x0KQxMM!U+M`DnZv!~)7awy}Cruoh% zBqaJo|E7PX)C&3bi79eLe_k6qJ7}bczn{%^?)f9Ug;r6DnSNxN?s0+ouEW7|y{Yy{&}USvw9`$QtGY~O5BpeH~# zV>`b67SoA^0np4wPRWrI+eyrK%xd+|7~)LGr?k-S`}lx!@89^2tP%;w4Z#D{#1!$- zLD6F*Q36MI@1^&}oA__Vpl@?f1e>2OMFa}oiRhU#1<#*vWL)9cb)o0ZM`mYdH#Ro94fwbrd(qwFxiMb{(UjO^ zdp@5b$!#>t2mNz#azf$3sYbM+_`qY+0%0yLrL6XDdMS2A_)O^EC`4jPkJ;-{)OmS% zL*?2!J2P4=2{H(TQUnuS?~*(~dF%u$YwM`U$hklKu!Iqepd#O?7SLo~S6h3A_5oOi z)eu%4@#^Q#d;9wSBXJU`zz*;ve9*Jv9rBv9R^Lvrb8xT*Kss)1Ys-51(mo3OQ|k0- zM4!<%)fy>C+8{V->gv{+7J$SenDhtL3-6M{d>vDB_RL;KH$~SonIFf4VjcWPiR6&M%p1Ns(RFMJ`&KJJ^<fI=Nd;ZgDAo}Q$V{#e1u=a#dqva}HNYmIi^AFNYX=Bd z3#c0z{r;Uf0PF!VKM1Hu{DOQM7<8|!2q&l!<+J4TK^$SqJ5KK>58S@Y0WF+pcmjC{ z2-J)^(ws7YPhVtk6I%hX5Se?-_aKLZ)c)-{Z|#RZKx}|Yop-qy>4l$2wUQ-cn?R1N z-1_sAj0MdCBJ06};kYkoFMyo^4{?16A0udNlm{Ug0ZZd@_X2G$NJZfizdKWU36YT>hV0*#l{LqUfL#Cq z!R>Yfhs0H47h=bwUW3f@#PmQWff^L8bhcWIWJ9*8lay(f{~=0Beh3f{C5(-mhwML8 zSI=J#3`A+({PWY#Z>FdN5}(8A^JKL(HSnQvj5>_{{v7mM@sEk=s4=T3FNb6BZeyV# zLCnqfSBv~#MZZl^aPwEX)QRZNI6*=K-jqysWGu-V?#PpFttM@W_-+VC)vKtg7H!^( zvOzq?*~O&->`KgSR@`GDH7Us${u7wfP<7BD85r_DIL8b*a>w`t1b!hp&lUg+xZitG zwa9>hkumY{<8K%bm;&^2t6c9xZtUX4LzlQo8X*XV6Y+om-OcK|`=ND2M-wd}xX>T! z%$1ZrKfe$H(E~^*hUd!U$Vm0bJV6F&lCRpkB$IxQjQA4)2>`PhUu+DovH59Qd|xw> zccl!xxi~u;!wDenp9Tgh3k$V!bdK)3ix`&p0kfv+>ho)M&|ch=Q|QOOe{W2Zs)Ut* zav~||3$tF>%lcdP)dD>b31Cn91G_mXjvg(uYJZ9HdPzqIDJ{ug|C}e4Mi7vRDJeca z9`_xb2&@w23a5t2cZG$W-3(B=u#)M$8Dh{#P6dNlUqwVZp*cMC$do=zJ5*NjIh^Vk z*aidW3#0f|oz~xw;($Z4F`rp5P0mHoiD;8in zgo#C#;b;^hb#tUiplgsBx(sWbBSSIFff|&l{S-nYHT9U~RFq*T#i2vD38HSZ@m)6G zECo;}lpk|LiOS5&OPbW(@m>zDxB@%sJ#GfXGb{@W3k$?5Vu1x=JtPAt3C@O}<4L$8 zptRCj(^3dwAXW+Naq;mggc`)fae$qi7WtdSDH#}iFrooef|Y?0jcalm{{r_kq?XU( z3q4(^D~>_%#NaK9>Wc@Im6UM(u=+|3Z5k zly}wuZ0&E^`u^48GC#i8N8!52SbD$CBAkWrhP8F!JHzd>Z~qEhB|huF^^L2McvF{H z`ik{+=qm{^=hhoO(}}zt<~+(tgVaGe2+zk}Aa-WudeAq-%1g~AfHlC|+nZQ0C6f>< z#3P)*N@n`fBjv?~p=;G+jAd%CBAz_a)7F-aG*eeU$hcKdwxpOVSC#yTZmWv7)8@B! zB@Kyd1pCCy%*_Hl5DCg0os-ldhhz>)t}qvU7#w6KMgW~%U586E-BsH6K!}6*;WaB_ z6?~34UynOoEy1ANeI72!C9X@?u8njRT0n@4az@PcTUS@GF~ZzKZGkEDp6>44h9zJo zh%py-Jy2(ZqMp}rGFpik+kF1zlxe|}TGI;HC)%vqLV=>II=aM(qgAs?+^?seI*X_I;3VJPH)$Dg`bjp{@E15m*>y#FoHe;+D$=8sby?zCm07! za?bJgx%bck%ju6CktRkehj&zWbhw#*MjmPV?ZIZhO(#%LBvKF5{}`BWZfa6Z*2wR& zkxY`B+2ev0jEPCt%cO(7;)54 zLvgs#7JD~)%G`JlADSOsg(hqDXlHn)=FirNEjROLa%c%TMtMYhq4H;L2d5^0(B;ch zxON(vn8%M_v{-_l{9yOOM*kYXmZKA5Ec|(B$3b!Eb5ehPwPC~VKPp&KRyJb8PrL6x zP)fTMz|q+O}s2^K^PL4ql++3W?%R=UtxS}B$n45D*zBY7>++ShT zY+8`2c|${kkeKQ}^w9=E3Puf=*K`-4$Z|ivb?esa*8%|=E-pn?CdZE-zlV`5b#--B zRR&txThu&Hq%kOfi55th*9!C?e6>$4!D^LBKF!Q*0!D+IN|ua_Qm|}fbo60bT7@h0 z(q#X~Y{7L4i;)m2vSdVFIHF>sqeo|F6XWAIezmCw1q9d&$Ag&thMm`DRRn!Vn_M&@ ztZoDyR71K$L|z0VcTl+@RtgJ0v9d?%nSvAnKLUa9Feyo0qBI|YSX{5TxFItEqdHRH z<&@*wKnph(Vk!|4oSmAg&M}+2hAoWRTI~C0jp>gu3s+7hDI~2hSr1Y?ANFSh*6&5-H+I4gY;RQ~go`bI*rjsIgmFTBC zK|=i-!7Bnao1J~!FpAj^!0Cj9gxv?|^To*blhlr??$P7cf#{*DOS8H2E4r?!DXU^6 zUKkn|P8pay1YCE6%qo)~v$MbF=N12rcOq0nP7X26;IG_-l%Tt|HkC91-XS7X5`LTI znwejxme3ioJlOGw>SbnRfOv`~@IV_uPY@R`FD+f2?kaRI7hq*&Wnme@jz%C;*oz{V zosaL;yLXJ?&sd2vHGCI{0Js&?V+2k~w^>6#Z*4ApZXFMgRje)m2r`xm3dm&-&bu4r zya7Bzq_cS(!LjtzRGiEt5vLc0g>B8vyxiQ`FJF=i*@I_q{Q1Mr&yNkD5Gjsv$eaD! zcQ)Pyz5X}k-4pzX-&bq<9V?M9f;=%<9aEe}%}BmAnTzc?Oe&4noLX87F6Mh*y!Ax* zz6^mhu89$oK%NCWBA<6DM*izkHj2Ds*wcSZO(z8y9V$;>4ZI!<=cTkL?3dd%SToZc zGv-(dIy}Y>+y{i4)I0!N7PLgZ=`)Z8rJeAFNNDZt5KG+}tD@9gL=#*-lS-eCZOrU{ zWo3F`{@lq#A+rjOzbe|=?Z-=N+|h$87dP z_zc)FW`$?>&#|BQPs|ybVvRD1Ay5;)Z=RSlr(Nm+k`h(ajw%z}gvbDM9+Ee6=QGUN zG+BvE`!a{*wY?)fYHzz3vRsycX1GTovbGF zMU^z7_p5@zTZkBSBS=BVs(Z_6UM=jR4nbP{Tq>rO>~)_snS&b^=mD!d;FRRAimWne z)NH1~GoO^Br~Vyk{-To4u1K-=2tS-ff?E8jmW2u50sPnhI?Vjv80@~vVV634Plcla zXhK;T|Asz*7y_CBUB-5rJ1~z;LSnmHm7Su`m&-=*a(Y{rkM;WRnKIWIjBmny z+?*}@35wB#dMTNdl$f~r`DC86n;WJY@aXqtBtHMU0K4i@VnSg(6Y&9}Y#7KFJDpS9 zA6aik6d7*Zn5a>|Ze~`F;bHuF{D{^0%(iE9tKL`;u#(4+LkY#(r2KszODIta>A;dejxoldnQZ9jpit;TVMjsm*zp)ZrYYHnlR@Ld{=!Dsy zt}J#}A3$I+*Xd`D7cM0m|C!VU?q1zzdz_hh5V3o=cVXx*dfbU}!yz=hZ!WiEmfO(x zH$(#Yqc^nwBMX3~5=t*pz+7Zl%2#3fu)MsyCK-4NJTYGD`b$eo*9-KDlfKAe7=kOh zyVukg`Pun8rn)@HK+}YxataI_z>Rp(YXs@v-3aCmDI9a915p@%p z1P)Es0N=&9fx*gV$@T1|1<;t8fyyn{v30Qd3nA2j0RgXzi_v60nidR>Vpc^;%9u4m zKu9R&(IX89WuBO3+(U2gjenBQf17ak^c))>cM^_=$O|qRmm_=O0wQdNCHC94;68UC zH_*}&5f##(Yg}pjhgara-N<2TYFNUN zkredu_+P}q^r(90-_u>Qv$o|pGCY^xG}hIn7Zoj`*M6lbE_<~^gUBF2ydDG-aQ0wI zPPkVWD&ihKd>9!CX^)tpg1BMjlcotvd_B+aPgYh|gKgEYBk~NvAt70S)EOC==zl8Z z=Zp3~KT?m3jFcdX2e|^nF4wx+Ivy-FaBcE{hPc3cCR zLCOyx#pdSCA|sw?CHxMOj8IMK=;#PC(0`T}7nRl2zD+n2WA}R8?20^KOFS{lzkeqp zr1g`o3{rzbANsa=Vb|NlHp|zrW$y+CA_|Ql6ta`TN~A0>T;E_`1S$`(kcepO43C>p z^C1~->V_8q^NxrVB4q#(VPnO?P)L~mz~My>tts=e08Zn1`)$}9FoJaOF#*xhEW`za zi<>$077Hty0ER6&PjGrP#xVEovYm^Yo7ki*%2Kvb#Tuw@`L)&9=&PNW%Ei_SPRRq? zSOvHwQpvbclr21f#oBu4F^qvh6<*)@y$CGM^c4RbsAO{6jtN=JBEV+nyM1nMVC&BS zG?<@rYfzA2S0Y`bte~)hS=}GMwye)UKSDUPrmhZdk~hRt1cCFrG$4ez>>bQZPgGJ+ zI7fD~w`4w$#%KjEWvs5=EYIli9S63gA*A`PU{$NgF8_JVaa@p>=R9_dLBdl&MC1ss zaf$s9!u-%dF$f(_FA|vq;Rij;*n7SfLm-HzDDzhQf^{OM-!&E@zSzjmCC)(1$-G{rq=BznlB87ZX9Z^YZLmU4LV@0@>a~Y%sDjyU^_?X2mE#B(MSE z73GU?F`;=#dZDyJ*|E;6_}w$G`Av}(I#s-w8%V(3J$qObTcO}2WoFXRQd9rN@P(Gh z>L{-tM*75JuY?mkM?!^&aboy%eSTYiuu73j9jjw;cA((E@u-6#Vt2q)4S7&b`2Wru z3C8)rNVZ7ykYgrL(a<2D+0pjH9+{5{uVqOrEh8gixa8Uow5Ei8jSKGO>XNJMm?F!| zYrfbeYA~Ccc#Tq-mIdT$84FtrDJ>)8M`yt`Z%HQNlFYwfF|+EkiJ5!Em8in84zUk5 zB`R^h@A}Mml3)MYlnD+igjmZDEMv!;#8M!hVh9GEn{wdur%#=gew9%=(>70{6R%?& z27#`d)F5II)?ur|{va&GtHItS1&hgO;e8L4Bf$SKKj)Rat>dXr}vh`Csrfvvy zBk5M^I@66$76E1^>Y5ldAxnnDLlh$O-mPJP*BdJb^I!reg7q&|b{bcUSA(pKPd2c9 z887ZZkyONa0zw^3L}A1w=sREEXhS!(6QE0{Ix*j|0dWhZK!XhzpgUsP;5avT4MPfYu;nYmAy6r6#eA^yO2R?T&(2S& zzYxdNA0`70wY3ozx=SFA)?f->-_TIS=YGAJ=u7r*a0rOHEt9Z435zoVGjySM={w{C z9?GRa9NH`M1NQ@;(eMLX7^=xM#~sWhLo{}p=`JFkg{HY`2*Eha7jS~mV3IYS#Kx}T zIIEj?)Ya7ufcQYSL}-MJUi47R`ycy}1q6jzs_Hc!UB97N%wuBasp#YGMPPQ#rxbXp=amB?t%T?vuYh zmD)J-&1w7?LcNGE$%M+CkAybJi4<&(`e)aJqSkKD0@AhTjW9zEEpq6e5)8upPt_(U zs^Xf@Jqei6VdTFLydN6GjJ6z^{xWnh!(!Wnl&;f-W;%Be4EUI|wP6t#_?0^mQlk2U z7?jdiUavJ2B7ZF`yfTtW(4jtM@U^@9X>@ep*36F|3aYAog%;{ins61E;>G+ChKv95 zNv>$VO(w6O3^eU65}VDleb@J1KhY|ks!T(5_>nDDXvXn^IB}+wkF;mU3XVPPyd!sJ zKc!djef0%z0lK4d8ix)Gw313o-)~)SHH*1^)veO6@u!pVaxueBWygNMnf?T?S$ww3 zm`abB3de*u!UXIUB2rQ~Bm>58ohKk2p--+o8m+03Ezo;FfHehm7ydC3!z!iuNKjs8 zCJa7iVEOf4&_GjJc(ycFX=}&z>QZ(;LP{3`2|I<9#+(p<*C7)7*^A1rKJj|M^E_zSLXNZ)@`p z;ttTGU0q$p8N;oFPC*)9#RAWNPSfV9aGxJWqd%O5VWnC0D$R=*rPY)(UgglmWi2?J zos{riA&3=fbDiSidX=C5Z1ZKyl+o?LBDZox5b+mYv0=7_|N3XDfQL`7Yg--Gy4I=d zZ(8nsC4yqVM!vSFD@KUk6cm)A@`cn-|M<~~5s;jr_q8e&VL>>LONFj5?ocPnjJQoBnhv?+S6^r?$Z0KsJ& zMAuCGNlk;2t!)&!R3#x!N;w{4YVC4;NgSl6aRiS=5(V=>a%6h#wt==~!_Sx|bh zl`un*p{P<@Umv^ycHRB$8wVA+kGD5ebbJhr!wfn?9CpWWh0^}@$RiQTI{NyVO<(kC zr=#K&+8Yk;+s9rB0taFxboOin<@#g-J_;d%{qG~cYZ@OTg~4YVh{Z3dZm&it!rDWiZ^Kn-y zwEDn~4~h)%gQ%jwHMlWtj_!$cXf{JkqT=juOwqCIP+on(9Q zZDZy!%%b_CG|unZ&Bm63)Svu?3oM@%?l6-%Mwg_feg_>QrjiiiI!%jaw-eUe>l<3A z;|XeYeTtJ?mrtuFiXV~ibT%PthpGxPNxO zHWxrO8XUW8xmQW_%b@Le}~Dan&2Yi!P1; zzPv6hjFa+{lu^(nV(KCcojiN@^E{3ig1$99tngf<37uE9JyN(Hkteef$Z&2mtYe=b zLxi2=jp;?~NcW9Y)fRw!5izk5&I5D;WO>QYw~kH^r_<8XdZYe+KZW9gXXtU{(&?FN zYd}Z@x{Oyh=3tcJT^Z50RiFDxHH%8_CBo(DZp*znEVdhXcZDnZMQSQ^gISS+Ru$t zG2B8WRn-cgbypZZ{r%7HaaF&wmm|oa4WfnO7vSfjX~E{kjcjaa@R}RE?eAZWcm>sk z%+K%SkZ8ksU2BnNf{SBeZjM-dyy4-L$;_{c8Q!4qpe`!v>UC{PKnU_LD~QKk1Ij_q z>l;z66?UjWMFj=Pwo)y6zfifsx(7-euAwn%YPRC^%)4Z2!&xB0_Fg2gVHvL+-1P(> zu(gwvl7alO zi2L(jaqa(qJf&6iFqO&}_&U^`#6I6*BaGZol9E-TS}a z|K4lw_g!o6ZCT4uJC+9H+*elDM)}5J3VOilVfB$^)SAk4`&H9-Kd5 zXV9(NWNH4%wY!^ZwcfqeJxaawdinHe7G>d`xIbtm>LgOpAy-yjJ$G(;+3KP_Q~X0n zlx7SGtGJeY>7k1*wQ&C}rTev>X*t+8zH`6#tteMMYrTrL_ONWL;CMnX-6?#5d`3oE z!vB)r^kUe`&)aIZwm^HlusGuja8<+Ge3P4>*Na~D^rAAPM0547GC|$XO@RR7=n(X{ zORpoz?%_{nnT}ISUerf4(ByW>tF4DW`&6kr^qQKYaC>lOlh<}OK-$U@B|9CPf?0h6 z8r!$u&=@{E=JRK-ud7$B@&GFP@TikWLbmB^y1ZRSU+dP6;+-o*W=952QU>nzA#-CD zzpa~%O$u^a2$O(jk8f28=)Fh9_twXbc0I33o1!BE6R}O}-!bCk-l3ep$44)_%OT!$ zMERHdje`fJyt}s)8!HNU^Ng2|{#uxdk`JbToFo{YioSdO%Li4Y_kZ?h)A-&;@PMqZ zH%=bVFzAWnKnf*^WujM_&5z1-=J{-YDLvM2{E^3>RZBPD9OxVFWZ>1d*851Ng0ONs z{xo)|`7Z{#UXt0Oz6#9f@bTlC+rB^Uv7x)J$0M^K|$xkbr=f3%*9?Q$Lcy34>x9;3Do`5xG;?y>*wxwlOUD9*>>Z zmOb7#{LdcNUwOaYy%hBQcE^z~L_}1bJZs0Tc zj~GE3C%`!%m>dDWQhgUKqB;pjxB(|+b;Y^RVTR~Ja2Ntq!4u+(MTbDhTRd_=_UEdy zvW<8vApyN>44sNbz)lkr!TaeBR9<#4?aJonUT}xt`~V`ca4%iFxMk~B*zFLa&<@wv z^J5ei{2$vFJdh(8nnho6+@*C)@O9a5awMkaLyV-6#4 z5A;;6CArsC_V!jr zHSy}%Gis|*2+#`Nl8-xCbLvCr@@j9?+a3Ga-BQx-n&;KBe#{#G>D4PdArps?0(!PYhrH>vph9WLE$+^;mem$nZ_;6 z6~`N(?2V7z{D;owSKOSPb-8$G7B$J>D^n!V{0ARzY^n%dxg zYv%qY6#^)vzeT;w)o5&cv+wfdjV#)?1&4}SV#kAE@S#YC4GptcsHaRG_AffuSv6Mg zH`H2k5{aJjdfUI$3d_f%I9M=2AkV=lfSK zYQ@7-2YQs>yVrovTy3K2q_5BuYjB6*fM(JViqW4^WB;(zD~ojzKnR5}N$S#?oX*&;18}2Zb>7U>Pja zys(KO6ZQV`7@gGp2M_v~q78jQcZtv9x?;sONNSXFZ(7(#f-&yItrvoV9*_w`yqTN7 zAe8=qxVZT1eHdxA6)5{&O-VThwhtoTr0Q%-)dH|!MF)!g%;!0FY~ZxPV5A)+XAmdW zq4MBjSgRY3z^&tMuX1&jA27hoH36$ZBhd4ILC)k9@PB43^vkPJn7EbC$gfZI?_3;U zEs$M6g~hA0_5?07rBkTM;}uN1x6lCXE_(4bwE}N4D4ZA_~;Q-3{v63 zoSdCFST0)h_Bf5cVGWaGDLQk^9#=nkg4=EoZo}2po*X}c=_R&*VQS9Cmhnl%#w9URQ8C+!2(erC&ET`l1p5 z1LTl>QeCZNyyMg)zjUka#S3PyR)v7b!g$?6HwL>P#qC?0Ve7KjFEvEjrgS2M-L`2{ zUhA7zs9?y;w6(R>1`kel%rElP(V7J;E&hswEPMlbeo$sVz+d(m!cGDxuq)i1BH_IzMF|i)|WH>pVaa#xXP*m01 z{Jxa6q>7B74LFtkK`H~US11rN?j!~5xOZ3+%`~Xem*!>zR@neY@14U37g3o(NwQGd z{qfVMEZDb*70H~bw6ucFBrF4naEX=k{ORb+1p`zC8`T-UgFl^cI zu`x;79flqg&n@L0mE`5yLG%i8b9WWIZEb6#+NHqzi#f)#ODeN4ec(IaCP&Z4*$ z-3#FgY66deIaiF9s6+4Unb@L;F6>!4V&(F7$|M574ie54b zvs;9>-|xNyWFa`H`45!Zd*Z%UtC;^BNbwI}@Fbx)LnrH}y@?ef5RT91CTUNPJAYm< z)ud`-r=yIdAi;twKXk0VzQC2PwpG4x8;gsk3%6+kzbg@nh&=^c!Q|(Y+~WiYc(c;Q zMUT^ouC2uGjjwO-1d(B_CT`3?qevr0QWczd0^dOJhfjyY*7v3wkix#k3$w~>HDm6r z;zTC+@L&{9KaSelFX-UF(VeVTsrs|$Hmp(E=Ug^xNEpHi1W}zHN0Q$xRgR&A-2|~V zAwlE0HV+nVXE*n1{ZIeF1=wQ>DV>AtGsvlq>3idjA6Ble4Sd$iI-!?lOtbJ*Iy8RM zKeG=^&2_#^UB&*fSU1}Cxb;cx?5vxLgNxBebQKq;^@0G2Yk2|c2!~K*KZ$Wj&KGiy z>&KABSzCuDZP6u6Q)*yFN#99H$?`95T;~viN>`=t0jRZ2eqR7~zF)V{9S1$|*Pow_ z9t-DdMc^Y4sxSgX*Lv7&o{TRVDpI}Fufw}O%|%Uz&m~AYp0_LR4|Km2lbYK1%)Uz! zx{aK$Tr5YndpFJwEMDr~y&IsYs7MFVY^|;7lqrqRGjMEs=9b;_!D-hIW#oP;@L|cQ^Y+OL7cA&0r+eqw zvy*u>rwqMh9ZT-tU%PrW;E&!P&&HRAzb0!%C>eU%{`K|*L4HPFXT4pEnixo$w)b>N zi&OfeQFWI*!4tfyvhua*x0V*Dw#|5>zD&3~ngCREyoiiu>DQNdeHIo<_Ffb}`?x#h zZvK_jqFlQ(3#KWD+;E^n1zFelF-SyQ_${pqLy4cgsqiFgdO82Kro0g!KP=MHmok4` zRaaH=C(BEViECu0g3iv|uyxd%N$+k)Mk4WT@XbQ`7o57@$K|L|m4Icb&NZz2u z+D*@nG-x5V%*Y2bI+-3hI}VKlJw$wkf)xx>xVGhF=vb+u*u+iv3;b|)mv^lg4KZS6~vNQehy zv<*Q?_Y*9RymELM99l=pO-CP&A9Z5#;tVy}z;_Q$9>r*^tgN}VsNbo*4K_HGS=zts z4QCJv59LB_#Nop-89Oe|R-c8@J}!Rv`Vm9`6KKq4EdER_M|bR?wC<=;XGi`7N(uFy z6S`(Jd=+2@PDx8ciOBBT%QFS)oy+D4OU%snA66WV-V-pa4rr zNqzS=a`-TGPxy)xZ1cA@m>Z=Ee>w>{HD8$*I z9-l@H9Xd@b!ga1sf?RPE0X6fGP^p~jD@($bIzE07k! z{se{(IXU=LWTf4vp1^IP=E8Y#z22LQvG9!01z$Y!QWc6W>R~V)4H;qx2WgF=uJ~l? zvEe7ma6CmL$~=|v7s#0AE)I=&O9l?$Kz|?Ei$}xEA$^;F{G!(rIwD3bNg=PecvjU2 z`k)1rA+~Hv3Xg5K5~7om%un8LJ1}6*{6X9Z44IIURF;gQacD7+?~io0O2481<-!yXxFvfp6p-Bpv;Ez=)9}?+$+t z>z5W6#NV>(yHOWCr)6^gzEp4YTifsrz1KW1j4b$9 z3#JK>p!`c|J&~LD-{(w{l9ry1!NQQ!w*((~#6pDykw!kA01Mac5M?idbV6DgVFYjQ ze*=|cveIhq9Ox&2CzSL+6!c_^Jij}?wj6#so(S-re71kZFOCNC9)itup{8d5fD5_< z$tbXAU(!pD?y&H+Vc(I=nV;EZ_Vq~^#DdC88k40-#jrifcc#CO(e6ZQ3WVfj4Lrub zu6xM~(*j^HFJG=10D^x#1J}$jDCu4gue~ZhSsEMk#JejKXBv}kEZ&2Vgvz5X zz$8L0V#V=%XR;cL^@qxz6*3R!PS1V@5ob=EXrRfv;_TVIVB|vW0i+GEsUbr)=&&(3 znww~dA&%9d=dR6k2Samo0nTB`uwW6u6xS&kdC&LpS-)n@BHG^q`tbEDK)Rl*$NN&% zzh=PZ&}Y8X&b%4dw1*umB-Zrp*Q^=7JBQ_z%gU)MC&+u#Yd|&r=S`pvcI6l>laET9 z!m5Yt#(FW0N}(#mqR^w;oKP_Bb=2GFCpzs^p~nq<@K-&21hOK$wIri(7`yqdlPWgO zU#RWrEMOkYmZER2aZUZdL;CC1uLrOu=Z;-iPpS#3Ob~S67HR0Ul|0wup~6>gFLb}L zBSu{0NXd6bIThaH>X2&vy$Tdjix>)$ar=VAI^AdX?Mb7moUxWC$e>m6S+L;vV%

zcYP3S`0m|{#z)e{$x->}r@G3qWA9_ohV(cr^GB30F>_;_Uc0;dlQF+peK zw@wK*)BFDm@;~&q9njBI17Dp(d9_a{9{BCw3>54V`-=-AOzGX+r8eRUhO6$AI$LOQ^byYzSbx_-B7;!I!2 z3FPD(^%Z0T`_m8$51;bePFO%s@7;3+Vk1y|DscB6@oQ6W-*LLSh}$r7k{>kH4rg2d z1mP4OdLf&^Pxyqn9Qwi|CZqK%>ImDUuK;Xx;)MLzb$XGOM0h;p!_HR`Ccl>i%0Jr% zloL85wxv!)O#y)W`Bk)}Dt*RXDl*A)N9*e5hNlO7eUc=*I|3^!-jZN^c>M{LGp%94 zQUCEAu3>)**x0LEw;bP<^6&TI+s{WL;2OLtEh`&6X3X2KKRj+I9BBLZ9TuNFf8j#c z3-z^n6Z>;Vlnz11h<~ta_+F+}^;VNqgW7?oOohAZUKL6546ZG1c%+ZHm9#%ihGolQ zlAks{FlK_a?;YJ@ni0FSOPDd(%%^EI2EQH?W49pjW7}| z0nI-fW`mtQi}3L2B0zvj9i0%I(*~~Mr;BPf053bH%O-d2wQt$drDZzNK!VM6M;(Qq zCvARk#@O*eeNW6_@sqC)-G{AWK)f|Seskx|vF{cn<=(xk&fQWAeSUL$xaX<#Lx)QC z_Zf^b7z`q~w<`U>F?xDXSQTOM(kDbS3U)y119K9P1e8stxBi`U@MZK;prHuIsaY&f z=p_Q+f#%j0%>k9Bs8?54C$@Y~S>-#CVs1_au(;qnIkpW>5a&z%c%TXfoB(+V4#zB|T7^TEy1{k~Jjja}mMr;Pyd{8hB1PAY6Yf|mNtQgy16<y1cAlJ%4p!kqx(=wt5wC0I(f{DLgp-z~T&k5G%lE zep4QT`Hcra8!%uS(VteaU_cJwEIwJqU!u3tsZ*yW(ZMAI0I~~Ur59|x6fhCND}7@W zDjK?)0CRFe@@ujR!ZBT6iCec; zSEy6O{@VV&Gz!hLsU#S0AxtbvBJjh!nmK1a)Ye|z_;&i251?;czg_+APb9q?d0`S4 zb`bi+gvZLNSGgp#6g_$b3Jgf7knVE!%TEFJz{Eic#mAu8Db*k$l^1R1h{OhPWwOx3O5}>J4EixOnKF*F=Y${ z6D-E1b;pfU0+cZNrxNp{!opRwcD~zI?e5z9?wva!QNee3W~_A$nU_F05H=6&-%m?U z?&Je7UkH$bmllp*jg$bMt*-v1phuv!RCRQ|gQV$zF3#MndE^RNHy?iOt6Peyn*mQi z9?rlAyng+dw{)bXecUx*V{jqTd}&jT`Jbd3yhOKMPtw-d)34x!mo|mnz*+H~ZDg0V zrUPV)HA`mlo$syNA-DtlAE2fy;E!Y5@#h~gKjk%T>n8{0Tg@aXB83LHWE2UHkRH}r+QdZcQi~vXjtyVnWR*|!9&}#Z=*vh&AypGcosapn6ecQ zPE2!vX^4LxkSbjR3T+*oMx@OkqI&W@haqpU?Zz6fT`BaAV$?!s*lLbMDK^Vw2JoLEglfm!vn=6;u9@A`D3o*fZROrUz6s<(%) zPfkFk&tKocH8p*?nV*xInR&u8J{g-oZP~fW41@!5!;tswh!bR36=h{|DvDFptYHJt zBgjZEq@zdIY_uGrz;w4)w4m({a2svnt|6r*i|&lc#-d*P=JJ?jx?j9-fsX?i)W`I1 zm1u8gr|Qpf!EI{JBFI;})c)rZkt^}3QdUI}J9Voj$9CeN4V44U{!6l!`|5;Ho0F%6 z!%5`!KuzsbDS^pdO$&u@DBh$IQOvw zk=Q*szQX?E!u)q%akrK>1sA6-AB~elbMu0$tNLh~sYvTjm;jGQD>w?}HK@-QJ_Dq% z*Vays4-$-i)3oU+B_(az@zuBka}u`~nQ=iIsS-JF0;G|8iBArhV%0Z)#t)b>IkUAz zqTdfGDA4hsLm!$g0K~>P#PBKtZ4}?-ohB+W-2u{cBFqt7TSZQYIB|j*CCrpzXpF(x z08(qb|FEuRa0Z))9)@*C_2e)AV*+0Md+xNLYS=#Y4Gp=z2^v~j?X}@nO|6`0EcRjJ z$J?ug;uOdz6>%$h;+_w`k&pv53yt(5ldxmQ^w(8irK?TLfYRdLYJt?iHVL1Se(Qv_ zPdgoe*tj?v76jB0OESS5S1mgwKqH{(=(H;yKjso&z`1|32{Fi_j^n#?o&^$*+6OGm zzG=D#Nno}AkM8hD{*@J1rs)X+-X)spmIfy88yZ0NXv&UVb4pT`Q8{bZJ})gbSu!#% zdipx5W{KTpPo8LOdvWIuLr(HP)Jk29PQpBL)|Hm3gRbRRYy-*TxM8PmiGOVNl)pn?MPWh*ljS$cL_&>twfPcvhO*;Rt{`tF~cASl7WUq~a+|lE~>$yQc9oJ^hpoT*v`CCn(f`}Xj zjyrj=LF&%YDBoSMU?`B_3fw))S8lJ_X&KLzB3JKwpnZu)wqn^(X-QnMaHB@8iaN4t zaD+Ls9|<*^=s$)f5N3OZ2u4<-Ci$J#D#Bk@iFOIs_y7H$er4Hjn3fP1H}p)28@YvJ zk0@QSAnOI@w6EB3554!^e;RMku1nC8(18 zH0sneaN-}sv*~$09hZN!QkV!D*B2Ni{Nzaz8@;A`f+4Y+^6zn}&#~gBYs+cPK~CO< zJSBz#f{n94EwttFVB5>M@k90?bXe;+-15#yNs(4Xc3HQ<0 zxP91syiw^Tkl#DA3BCu+(O68vM^M9EX~&-*??_RIoofETzmKb{Gs%6)4JNYh;^Tdr zXndnRVgN=f7XwYTSbg>}jvj%^j!FcJ0gwhZz0v5=8)4Cb7t*q>0RJAh_6hTw@Mxl` ze4PXC%^T+nCfp9>CZ?+hdz^BlsvVAd6)w6v7Q zPb!c%a|vj#a1mbCN+(pSVKSH5yByfj>x%@|yq@%}P1`-wCc;<2p$ zOlTbWk16AFDrDT9Bo?chrN84-10Us)fhUo zi?5=t%l^}+l^nhgaVwa60}NUi;PwdKuf4!5^Ggr@b9^s|yO|^;?~^xE*FH^!K#QhA z-mR%-gTACHLn$5>B#G_2Ph0O{xM}vU0bTaZ2ch^yk{57uzjQT(N*^CO$i8k)PJUI_ zeSVI!>*`+9j~D-LR%Sf77*?w=2{>{hlb($+=i{U&v*lCX^6kKem0S}B$Lp^@a0b$M zO^UyEZ5+n>JUi}Kr=6n4vr*HX4X_Y|OHWNi_DJlIFCtIj>%geDyuPgm+RXmbn#|n< z@`C>3UrIqs$qSzo5FP^T7q|=gfdc?U{y+s`){Wwr6^xpy>@iRXHXhIF(>oSiTA0?r z8&FS?oiUj)hqII?s||fxt&9#P1D5IiKBdp~d7fPf=KhR<+kpg*MMSUgA0Lp)vCj11rxTMfvU{6WM6ZPX$=P}>IWU!v zbNf~26Ioe4#sPyRb6GE0SxeUYn@RhVpMuGpiLL+e0oRy@%yU`@T~D8OplNg@j4XwP zScb>=YJw?WJx$Z?WNkaz23K4O&gr~A+L?A)2N=J?eTZX zYKhtWIyh)No~Tm3|7_4F<)QcCe&AnCx~t6tNjreO#&(n3Wm+hE2rSG_JH`(y-~_n09FC!p2nTw28_NhfJ6A#Nh34w3Z zN=ohl8@jENYIP2ah`t;=$GR~@$MH^Vzoc)|aU}p6JGwnYt#X&wk~uvS?se*1_OL~# z^SYS~_&Yk*69hWVy53^9-ajVW9!c&RIAQZD7NVcgG()&pR8WXzBvskSxStZR zTig<%#`oA`dU^h@+`bN%quMVA-|RN+SME*koUBRJ1DhVWt(2$^1HsId9fglfTG~3u zPiOgPQ;i?)R}*lJ`|rMvTm8uDKezy0I*I+kgcZ*29j8$=COKEw#xsV1CXN~-LuH<=9#c_oX=zC(UQ(4u zh8&-&?7-ArbLlUkkSBH=pG|kd-%U`pC=?`c737jiLec5v+2aKIOCkoF{Q@$6t5xV1GDZ zkd|n2(^thshk6JOXVcsn%WN#7j!CK3zJ6W$@@4SYm6zwU5M0D+ns&EtV}6XTF8UGX zA`cylWM6KqD+4U9{pDPPzylJ~n1*G|L!_f{LJ^r()D#vGVuoO8MD}#YI3ry$=2)0X z-$990*p^>he4Zg@L;7lF$_7nm#SGWbV6vlR6hH{~&6YG1l_!01O0UDZ?qyB-oKx}Xc0@0&&iMQSeHyooV`m0H=kIW zM63ZRxlL5&$Y|JaF#qHP!jB&W=^ivC*toKRbx=|H%Ze3kzkY1Wcw~|&-nwr8DKUKK zY0R>CAmS^ncV1bM8W~zKFVPJr8_r=uDlMm7Dxj}Fyp3-4=xxueW@sZMbi%Zbem|pF zg7Dt$W|v929~shWJ#^mc&X=D2vblmeWkpq0{@Z4XO|F9%pma-!cptR<_5e#nXV{S3 zzmL7+x36FGW~qC;*`MPCM)n1Sj2giCGJ|AJdoBY@Wf@~1=HQ@YS_tr3Q2_~m6wc~J zF755@HvPc%+rNLu8j*>Vy+QF_yvX9~!-ogv)zE@dV=mG;V8W?tMbJdB485VKdWX@0 z+OnpFMMX2MtaK2Jkf*S!+k^>P`fp22C>4oY-EWJ)6ucgia@f$(LUH8=0k8ctDFm@jcgOg8V~tu z%~vI(Xi(SS;>$ZYlV$;ry2o&BN3Iy8M?GZ(oe-7kLIj3S0UEU}9M0{XUT zAt`8Or5;!c7Yh&yL|bVFXtZt1762T`IyJ-juP5p(R&JngPnZT^d$2B0f!Q9w&?L64JG|eIRSgwofTWP;3P6Dbb&lJMs0a}r#SFntuT+dgIXG1c~ zm<$NK2ZK`}>3{)WFmu{sRKld=iRE+wJiWYluxAXt#-TPmHN8wSfJuF}7s@3Tul_n~ z8p%SD3(tii?p*uw6)UtpDP-@I@#{v^&zTL&{xwAp~pq; z&dR%dgMq{lk^$gsY@)FXNwUUh(*^^_2xL7VyDXc1?dP?|R!R;yFqL5CaYAWZOsxx} zy#RC>ueg<#^XAR3Ut2F(vTphEJ%4m|fV2q?bT1~TuLa%qAv&;c6d1vg?Uit80uoh#I zbGV;J=`;0L%1F|jJfeu%$w^7>Tet2YVet0xY5tUSA1f_$b91hdhs=pYvW=#d!$lc@ zm5x3%J~(?atXHqrJj68ODM(o9ffJ^0?ueScmUV$( ziZcwI2zSK>AF`S8!QvxDQQyybsj2|!%4MBLJ3GV!6quN-81yFI1!LH7#zZWnlqR%++=@z z_TI%75;I&cT>=lGxW>&MS!_<1oP?%8!e)b9XyqJ2Q8!+lb*J&;N`$kn>3_Vr%H=| z?$Fv(T*ulC8~GBdN%|a}&>4_SIsYL~StcEQ5;h?ZFIl|PH;T>qVa#9HS_WmI~){ex@zd_#Oik=kc$>o({! zLFe+&+>=!Voo0LapmVom^c8v;SOnztFVEB?MRw?gnzZtq38P##9Ya%4kYf`xTlZH& z--NPWlB%wv!jh7LS^fEVq=L1Zs%Dj@_Ec4^m=$M}ap_|F*1bs=wO*age8ifq(oU!u zah=08)}NMj>-18IxSrR`|4Fy1`V~|+*6lT-1%B1IXApQv2M*O1gGC;&pv$oc<{z~oO;qPvVlobBvm=Q*$12l>@6C;G^^rDY{C!bJJ+OX zTo{%1Njfl}AO_x3RzB5sFojzFClQG+DUtK#>lqnxM-SUn)Kptut9QMoNs>p*dUJXz zn)QD*7kR+2iYiYY74JQf1Jhx}S5sfPBu>-JOi#$P+|@=h!SMNUg>}IXR^a%f_36sn z9P!U9S7|ON%d4t1)0(nZ3cwjhXoPhDHR|z8n;nZ&JYyGJ4NWw6a{NS^xC8o)dN}k= z1J}v~GVzc{r7y#DcDHYx4j}3#C9k*Nb$F`ZhIa#f)z^g2*XHTtD{<+R%h>55QxfOL zUJ&yw`sbU)KU;1c7P&2hJ`G1CE^b=0+f3++AI<5Na|v(UIWNO!3~@0=LII-2c|P!) z73YPbg2IME`YJF?>ci)um}Dj^DWpfo{^uiI$GRr4@}SqR=1{5~7|M`tOTs6UtlAcS z@!Ybdl?1gY-&Z|cli}+tN!jeO7LF}K+t6eWZyta*Nu4MwoV?ZAvTJG!L*3;HmMrtW zOt(JAY5x5ADgs%WBiuQA;DCgfn8Bxa+bw5AA|qm&s-rlCGe$D(Q|b~BudV60lR+!THl5ZLa=z(v7IrxtU{~$8=G8Aq$2cr58X~cK z>B^Pgy8nszqkHpVXxto)kM;HNO0kPx%7uq_ir{1;0mB3ZX7m-#<>ETZ&DNHd8FA$} zW4PV}Kcvhe+h;q3YqGDxi|*uEd_uH1aNOEs%-Z|gX?gtu5)f)Sz+q^Yd|Sicd-kcz%5r^NR1HW>IKJ)P2Em zgN&aYPPScmw~Ub^>FGzSAAhc|r}l0pscvez-LDv=vi9}-pzVni*oBWD4=6EX>WkLr zFFM1AQ$SKb-F{{wQ|~wh3+*>qt3ibt@{@KgG=n9rhkSr+Sw0Bv-{gnQS~hd$_)iRE#6ORCL4TmM_>G|&G)-LnNhRj* zven8z(8m;_Udg++7D?toXRmhG=zspI*yCG2nEg!y*M}_P^UJKjjx80?FVd6$1noMv zqWJlFF&*{91t!j;2D+S_AuYZ;r*wscLZHv(s%7#)n8%UY*Tc-MaPIz5*aIv|;gT%-E zKO`RMzmp*QJzgW+GQN0w;yB%i?uUo#2W>4~weHgh&G>Aa&Pg^V787Hv7p1;H{h5ON zSnee{We2;6e!G;-TBq1KN6Zt8bG9?sd*p#meWq*DuR*yVdLQW!M|{JwWNBSJRkHmV zgbTXr9IG_py}B&P_dT&)%%m6A?XD@}61%cH2FW{4^pJZC?agE9KW9WQt&T-Rw02jk zGcLU;QZe)L`uV}ftISwz-~yp1;3x5VKO^I48H;cN{r}aUZ?_B=iA2t$a>M(GH)p1a{Km_)ca)J5b>#kBq9zh`7E_vgYyAk(YYXgR z$<-R2Rp)oQ{Y;DrA*EqE6SRe&{v>*&DP}TDB0ANiRX_nnJzGj7&LGd39XY}7vonJZ zQPV`6qe_4$P=IEvO2#(Cx{$DYMF=;BwbAl363FjDY_!f$%{vR10|+z=Q_rkuEO?(u?Onv)3s&$iEpF_ zwcyH%NG!lqU65=lDUForzCimC93R3Y&~;baO~QMq$lVSd`q!jw=8PG)9XV3@8ktP9 zJ(wT_;yCQ==0WvbLOa2EA{PEfIz=B}0C@ULp&=M0hX^|J58nrZ+7G5Qr(POyqRR2wbhSp3~ z!kBL`F9O^5VRQ>4%xUFsL5c{A8Q>g;hISfCH(@bRlhd-H!R1ay4Y=PkVXvrZTP~LF zfdBO4DA;L4*;8Jb?zfD`$QcCw@bnn!ffu)Y23b|X2IY<}wz5jTcC8JhAN=(D8|r3# z1wme6ZrANf4HDXu;v9`$L!qxSR&E z8EL6JX2n5@+f(X8;I5(ApaZtj$0sXVok0y;ECvs^IF*kdU%<=@dWC>!=P!?F>b=tG z-57|GXx~FPjEQIu#=p9-Ff9pNofBtKqM{JPXo6{p+5e@#h=i@7==;Q+I(O0lvLj!h z8!`h}Xvi&8{b53L+HvN>n>7oPZ+$qiQANnJ5lrMeZ(P6rGu1jPnR34=A3g<%1>x4a zth96k{|l|g&@l4B3fxaIqosHb9yFebzcm!)O>>XbyexoVRp31u=cB*F)*$?fLLdJF}A zm6Mm(a$xi}?lNAj?S*9}gNx7j{yE;B#xNCF>FgDBR3t8a4~RP&dw(Bw{9H;(Df2RY zjlfGVN_1Vn{$+K0$CDe4*Uw#Q6MJp7eygeMpiYHKsgvjQ>9aWD`nDJI&R=sS9ZI_u zc`f+bwPcdkoHehi?LR~ZKkhRBc@Jq94V6Oa$tor){?cKul;8b+FU!o8~M!Hg4U*$4BI%1avWvz8zD3t}Yxg%^F4_#~Jt$?FXW$ znxl~W%n;|ZW6b|D-R+D+vW})Exes=Akhs9L;F@$2VKR$g7i=ydnu%d#-q2d1b)e57 zM&5BAEyC*q=!T&qr5)9KZME!JUdYd|{{(eDQvwDlcp}f3ArkF0DUC7f-Tvl%U0oHh z2sA?2l|eGeTV@u{gCZRf5^~#Vl&p@!S`yK<4YG!vUu16i+S*E^%aL_lzsDvK8^1k7 z+cjmSo^7Y|y^nx$MEV}|V}xVlMm7HlhjN^75o979?u(QFB2F|4k!WG0LfAj-uG&4+ z6O$*4ZU1bxbgAms4F5k|SSjs5`&`c>6@6sjo+)K6uhXhgvFhe7O9!Ekx{iS`^A9gjU z4eC8+s@365SFfyKWag2i+7f^%+b4#@v0NFnL@_*5S?b4WbNO8&CrpB6x`S-kY4u<2 z+{w>Y3j>-W%s!cXs;OzP;k76-e%^V;7oZ%X*?biQ5Az@xjG&U_E=*b;Asa|_#b(2r zpo#r^_35qH&|6?4Q(uOuQRRH8Ehexsk&m751&7P^OcuE^L@-dXU-W*O%Rn75zp3|# z$wrOtVy`a@mdw&E^iQWBL^8*Fx@)#1Z^!9+ufIP;q4Mm{Og0h}MU)RplRV~dW;%ox zz8}OH3p&h3rnw4z0I-M3j&>#QIUx_w7%JlB`3n8|br!8VQoDMdlBYGjUg!>Rn_Bk- z9QGSA%ijS+K#t{3wl7#A%$yl@6gcD;x~n;A3*G`950cA)1gveI41w)T&3Xrpc13{s(V6 z9gsGal-rrpSJhuyx6|&Srjn{I;u6dUF)fsoI>NVv^ckq#hyNWsYQ7r(JKZT|>iasU z@23p>=X5=N*SH7Y>(EQl%8wB>hC#lv{7jYt_jQzmnv3mUXm9S(m3Z(@dmjfc3&sK1 z+O(R-i~Sce0n$p-rjzjVBRMIp>KFP+H;8r^V^aD*`MLg=e$dIVv6G6wk{E~F27M`s zx7!DZM-2#O#QiEg*R=N4F2Ol{qmJ%{b?A`H6rala%_TRqC9^hY1kko1O<-v)IkWxf zyZzFh@=PlH@#bJ?->7jQX-vg={9*efhodY1zC!1Hd5n=PxgjH&^`4l%FR%W~+R^jX zTHL|go}8Ons1a%TO>cd}vXrU+mseBj7>IAd*O8q(fAByg<;KG#X1CM5T+CFSm_tSY zgCqI^d7|ARkI7p#Pnci~Ac81}a3$!L0VKAb+QDc^VX}4CZUDY-I@-|;RL^3&`>>x9 zZM%ygPjA}1S=>*sr6)fUm7cfP2_u=zC4)Bp`Ed+mykop7ksg!qUYq~@kngW$(4nV4 zjvL-aMS#5of-uo-7Xh;ne8wioO|ymxGavq>2-f=Tlo0H95R*(FKXvn;QF6=Ium6Mh zIJYw_y;cM1v;4UQIK)kCyg9|8>Zx`+}fB>2RfJ zJyNg1?)k%D9R*apgy6^(*a~2a14uc26D&@FqQli6pAAX!-9F_Vg*6-68ehF~@Fa9> zTol5HRt)X1F^1{ra$tJQYMqS`h+r;pc8Qq?)BVeBGTwn-s0TAUn*(>OoG6+yJsfxY#1U7twf*@_=gEF6voNcj@LF# zmH}*sZ-pJ}7beSn%j<1S_luGT(0y1BlCwYXpdliP{IarsBR{D|YWudijoXH%IMH?j z3Lya7jTwtY19e>rS!IQ3VWqBV=&L4rwP|P73RN%e&Qf`*BF4HSP<$c`lYI6QbQH_m zb+X@y0I_qAGFFl?ek^M`u(&o+@9M1nR7UTEdaIQi=H=nhf&c=RqvE&Fdv#w3QoWRo zo|l(@!Mu4PT8g4tzN^t?d8gZaG?YaoM55bORjoV&pZ1o};yQu0hMbG}vMcrWQMWP8 z_!m!uM0f{7266o|IjvK%A|JBn8Ubkj#5bbcxqDFV3er+&0=T4IJ?^_@%h=sHDqTNt zn-=2&LQw(rmk0)Z{^$Ks%Rl5nGcoOOMAt)I`0?%A7@I`cky9ET(Hcj0&5jsaPu@C6 zK|xA{Sq-)5!guHUh-%$47G6Yd^4z~$KVDFI^@{;w*MuF%Qd2bEF-cwhAIMuGR_~^U zO3euK{>sYPYaWl}`J*^z1|dBWC8b-4Humq|PZWhFF=osaHXD+cD~X8*q7x|dzI}W; zMpHA9Jp(*B;+nHZ4zGN3j>a#7HGAg$p4sYx6Jpg1#b{O+?NTOn)TQy zHxl2F>vBsvi@1H&5Kwts$}vVT(W!U^@;fRe#Yr9;xLG3T6~6fKWO~ihkh#SWlfA>k zo<;j#y!h$txnt-3H>7N4iJ)M;nwq*0e&`^#o0Gdsh@h%| zesuAf0A)>nSfVIoDPtKBEs$M>1xcd4G;eR{URzS;g%{htem#HT0yDyZ8(3~ba>DLh zLG!@}Evj?JRGR)P&02YHnQ2>^jv4ZV(Q5I0;-|?lu%UnVJ)T*o7oVW#V5MX38pWCcfWh1h$|Ut3gi?b26F4*seVcJadq3VRWygVlLDHqX~Q$eSq$`y$pbf7^3>{H+qYZGOtZEH?(4c` zxrdC%Z^zjT%lIBWdoqM7c8w3tvy|!>(@JGM-uo@vakg-pRiRS6l9a>*v&C^X^{t-e z?PVWYNzAxG0&5a=4ABf{%(+yn)JViJ846+0UnduNn-ALal@ zYsA_7fMAVo5d#vqTsS7n29k^jo|Tlxv#|(qsN>vgiD(zN$LpV$)^8@SVzqS7@C(Ry z&fG38;;n~FnbK3v$ef&UZl$l=kabT}^P5f&C82cBa8W4<7cBEFE$PTF9!c1=r*2Y~ z8yCe{J#%b1Mj7uP?;Y<*>aTfiX+E!+<&bQv1?Yu9!b)xE(c&d+yCWkO!5IF^N4+rr z@~(%qSmr_@Hxx0iVgL+YS_my>=5b*=F3!=IVc&-P^{aoDs+rxvKn&vV>G5u-O`}wX zlU*^gd7+B5|DHV%#4jNoB+$a&;*os%E|xzcI2Y$p)80+0+guL_QumYNEY!n8M=-^= zG<}BSeBlvv0b0OOuo4gM{QNTeboh}t%idtRDN+#*LaHp>Oa7v!1O^mbDRIJG%EW)6kGyeXui; z8^6kDBh(S~o))=PRcY6+f4{uOy9Qqa$k&xbqv5x1ZXQdWmt zL+4t~ImetgE2E)3$CkfmiErGpWoR+yFgP`V8lJT$DL&ba4+x9%We;w?h$V0Jsw3T{ zD2#DSmybXRsDA7&07?2pM!ll!92FULX%A(Kd;cg6LU3oK55jl1gu&-)d>9 zu8q}KSGSZ5tiD1<41-*K*s${?WaeooD1yD380#azIG7hg^I_^2J^~^0%9j0v^*=&e z8!sllnRS7a!0IRco+tqWeHk21!iku+5U@= zQ6D>&Fh`@XDFG$OkYU5Z4-0$Q5_Iuc?{*lBNNiIn-TeitEB2Qy0UVD=Na02~-NfH$MKCJK#nbdF)tV-9hK8^RJ8wA;>X3!m}`Leakg9?f340M4;owtNcBO7sh)^yMoag`I&)Z=s61iuu{dTt@sdhR zOr-ik@TNOv48$5Qv6Vg28NYD8YVY`Yi((4KZ)wV0)@kSMreOD@w~q`pO_pb35j|kM z48IiTnwh?;S#yyglA}-mDqr#Z6Yib;GWJ#5QAH?gW)89g^-3Gyoat<*RYh)cX3`Ws zXxf%1d&r$v=>;vFy0)?P%05s8`<@wZzuz6?w)xj@MZ+l8A{Q~K(dO47p7kZy&=}d2 zL9$Ut^I`yPT8_5rWiH*Qr~Q8imiey%1D$=c730cHFPyW}x4n@}|iRl36ab zeVbPqCrf)R%CMCZ**8Y4HS|r3J$LQFomoFyl|Fweb6&cBTHP)mv+CK#s<)pNSHG#~ zxAMl-LMzvheZ}WSPsz)EX8oeHY2f+Z-`e(XsBe3z9G`j9iT(o}F%}58*^<)+o>2nO zwOsdZ$(nWdZ#R}WX3g8|`(e)-_X7$0vLw_WA1fK0e;SF=H4d*=S_&uib5xBOf#avChVXW~SK z*~PAp>P2S{g-;2$+}7$ax~R#)u2otmefq_=%1<}%dG;4IJ<(otSyJTEX~*>|d3$c` z8SFFZ$~`5A4EyIRazuW4F1=bdT<#xuN%qL*bL;Wyv$T9j2A=OU3aGv1wOKJ0Dv9{D)R^ZeC{lYQtX!v;RpRU%qx|v|B;1lWoO2 zMDIV5!=IBDnE`ftRAGWuaM(&Ha=3M60xn04sB(;B_(ZDC^SI>=%k4{a< zJeRerdHw}oOXXJ=Duxa?`e($1)aY9=5^5Le(vBI^PlRY4wk#QfYTpBg&4-HUfb|?W z>TE`a!RXPKV`IfdcY_sSLo*hB5`N4a8JtE`pB(H#a$|%U0TirAYQVG*0?s(+oaeLdR-37i@54^XTcmzttdH-p6+uW#Zpy>NJ>&Kw&Znh9WI`|LEdL6BRtdk!vtJ(LKYPtc047 z1caE7F>ep1dW{%0o+SR(zUEgO|@&bxRi%nk-TsWoF_Qmp%l&I;) zFH$PZq@XlI$G=3-V|)y$nrK5qWg`7L8uOk&P%xoTYhq+OYytS7#Tlc>s}?KoAIo{$ z40M@XwhHTE5D6oMaI`WH$&YQoJ_8Y^Qc*xjM~So}rYTe#5$4mZY1_q1^in|Ok@IlC zK*P>|4?6#?;cgrmyTylArMY;oUAaHwc|c~zR?B&niBlJk-2S4VsK(QJ=Gn-g{l(Vf zTtz0i?-m}DEcoG7QJ?&~Bgn+PBDA!=MP~QX>;0LnvwZa6#fnuH9db6du?dL@9VPma z73p8kwKg5fI^q0e)1ve1V;$|Q&L5MKI9jB4Km2pa$FoiZT)W@CW}W5!dAbvSe{$~5 zekc^7h~SAQE`oK9usQj0_#useF!MNyMz-OIdGTHw#m=%VDR8^>?y$OYoy=s&5Es@I z+mRs<^HZEAgYUx}$XX9oLT)w&>kv2LLQI_N)S|tV^DIvFXh8j!G^9o zs}`<{NUDhse4LynzdX-n)Jx?j+rFh$Uf%Jd_w)Pr&nKuAFS*~bNNd}yuO}qN8m@>> zYwNx>dtSZs$T81vJUl!Ox@e%zEs-BCF^DW)Wo+sy!iRBp&N02!eIvCo@%rK0SloBQ z?nWB&ci`h!wq*Yd3k?+$QB|x(HAWRkxd8A%>F@$4G%=I#9HWNK69RGvx#%cN8bbfc zJZVwz^W&`_RP)j~uUl6=X;YX{d`zMC!@70dM7?y2?uXp&yt-p`|FL7oe`smn)}deL zy1sqhnK>f;EfY&B?l~V$9wtgTURix?=lQPRK78D}e#OYZkL%QdCyu5~dlUV%&8C~^ z{^$PUo==W#P;GO)w=z$n)WT+BqK9jWvWQc$i;w4>7xzA^d~NG4d-U|!huIVBPqwC| z$-nt;)V&ER0V8 zN?$+zqnmScMtaTA(_hQ?r9B*(zH!Ltgbk)Q_PlxaA!26Wg`1wZ!HC|h^zs;yMHRGpzpD$zcYdSLA7S0Z@|7;vG{r>gr{o#+s{kT_J@_OCEYuB3n zuT1Q+!^ZgMrg1;reWp!!wR(@Gsvu~AL=hbWfC&t|L;`?DSZ@(1me%$Ue-)jixBUfX z{kE#Ai%326128mZIU>&+Z67xQ5lx$I7V|Sk_m4?Oj-$pE&v3f%8 zlfPrkl9D&Ny_bq}23G=A>1sMC$K zC5e-+J<5wwzWwWb8ol;1OH0)iSC3rZwq*-xDkYF2SQf8wcFv|l$<58hf`ZP4%+k%sT z&=MneAwODSY&!-WsCpiQ6ltY?t_>B4;dx%#$33;r-!oUVns(-M>!g|o4fVz`F&_JW zemUz^{Z-9q2nb(D{tnRZ_<4wAQj&A z=r#^z?~d7r3MU;9NPYEpGk0t`q?{IJZM@*)+vX3qH!KU^?b6qwn2)E)W?f@_xZ@JQ zkU+KU4C&l9_+J?5p_p?1FVofkd0+IOw;KPB=l<{h;Q1PBk$2%pCJ~u37TTlz|JokS zNnWDo|4`s}p9mU&h8DCtz_&X?x<(D|GusS!mnlhl?}kaAzYOiCZ_)+4!uIq;bA^)8 z;S1x7?3>+n80z`*=M}avwgJ@4<%k*_z9gyIMbkQB+#mLxNXi$-#btOXBJM8O^DnHu zX6`*r?5!mw@n1b191PsDeDUIzgrx4^gj!k%ltl~zY$SO>Kgvz(0Hk|K%U|y#+P&d{ z;fOglsU5Q$!*{&uflds0#ej9~crZ-Y)C7I~I`JtUx!OD*4hs7iBCS9BjT!7 z`gnn-enc*jD+D<#7^_c6TlEv7rszue!nPfzE74N5PtTrRJVDKAV{r8oz@_78lR@52 zYdD{>Qd61-x;p^1TK_}%Q`EnC1CN|%NGS+MOgX8zj6HA{c+09RDsw)Uo?D~bq2mgH z_V^tz*CLXVxWh(*SQO3Th%8-H8#t zJ-j=b;Bi+6N=gz6?gBpl&)7tP{!(q%QjXl!ic)JGlVZcGhGhq1b3lKwCzZ@`wrG@Lt&P*Y(n;b(AGkRnX##9A-?E_>EC#W=G*-E`I8BU zY@63NJUm2al;^6P(3&=_n)LB>$jU^)@)<@#HPDFEvvRF{%-j1m-d}SW8u7{4c}k|r zQr7C35>Zb%xzJ+Nrem@@W|(UAmYp5#ZJhZ9^g|u(d$jzS%yV%;B)po=3Y!{{+YyC) z1mbccV}qF%?(U4c9MGR=m+Og*0Rm=RgHb79EY@vXLyNnJPF5L}WO_QP#TV>UsTF44 z5rG$aorJU{jN&`LmTE!f&B#C_=1B1lHSln)elSqbb^Ky~tKRYxg&*<)s0##wA^B@l zpCk2ktz_iy%h_z8a<37NQ#CXM9#C|~JW=<@8!ysJTSvN&>mSp5>p~+VdnB-K9<<*R zx4wVKGnPKhs+KZOJ@m-Six$dK^g4?Diz!eVyDQepxa`<59y%ihdn?LXp2{&IOB{e% zZK%(Chy+*_$sLQDxl8g@CL&1XMaTJap$ut)5tx0_5?a0X^Va8d*YZ06^aU!38=Lw(>nR)fri z-|VQP=hd1XHVygO+$<;qMY+7()2G{sj~4Vm7=dMNsh+#V>kW&H_e~_nkw4&%t6t22Q~w}3igSZZHX9VIB}%1 zPA*bOpaB1=K%e+)(__N41n$35<3IHkXq^xaFE}(MuPD>nOu`QFkuslEg7esRVYG)x zOB-d{tW{seGtIKhiuo;mWyWZw4XpF=<3sYRd7s@yOgL=GlIICiQ8|3mj=36UZ^IX+ za~aUpBRLV+9g3edl0!v!B?TMx5MfIklOY2#*{`1&5(PB4U;0(t^D0cLUzVl{kWJV? zI(#$++XwU3Ff=V(8&M-+5(j*Jp@Oq>a@rxmUEc{|;O#tpr;6U|&w226=indkQi zZuBFaXpG*VsKI#i;S5z*t{qu1t4FhY8>IJg!)w@vY23Df0%Z8%wlopSoGEF0Jl9XKu3vmx2Eq9ao{Kh~0j!U!p*5fg@e9JX;`;NGN zfshDe{BTiHDPj^h+K~f96alUTvokdZT@`Ddy!^`C_+pr*1|cjI19a4Ld-mwa=)5Y2 zu}^n;-harDq*8~joo|Bsam=;N|1J?#Q}cWq8q)}anyi)n4qvx>S*XytprdX(}r`5&aF|78ho)5kqK zr^@%&NNi=DLvoY zH@}V2cV-*7{dR(MFG!l|(5k_U>1?=BL}lk!KUrkYXsCO(O>~jAzflhXGs@t(i+3G2 zLwuX)*H&7P|4|P6U%toxN=N(uvmg9NAuHLMn<7oFc=w`Si_h$YU^qc%L0rUxGu5*BXOtfLE{af{+wNn1qGD96!^ct~ zVe&RJwF-f_9gjWnpvHPAKhaTSUzU>j+2`@pQJw7mQrhJpmu@okWNeSc(NAs1KK*1; z{9)lnF_BNsGWSo}@g;wMsI;3#cDsj12fHUH=FF6`Aqxly?;()#)|Nhlz`Os*wmMqN zZje9}sh9*Q-#M2}e7X^3fLQ05$Q6((-&-~@^dXB{$9Sitern)+n}+X4)0UDxIw zZ5kciHZ56CDhL2s!7-SOTQc}$ zRM#j|@&R|V6tOTLJ^hz)k_iHS#h|0by`(4Dk#jXCc-!c)bQ=f8c%9TU58Ki)*(@xu zzo=E~QlCeXp%T*W-4@BDUH6mtq4yVV$4P=xpIMJb4<29)LY)zZ+A=uU*Ox%(t{a>% zEnl&08O2K1Zrzxyx%~VCp4Xh*!WacuD`ztkL?S_(|LUqygv0@SluT6zp`9?5;zIF- zbJ4kT=l*e%Fft+>I#oXkrjX@to>)Q%J;U|v85mb2B#4Wc)5f-fUF!JUwJ2@#B5%K? zI^5~zhSW6ZrHItkULpqcI293PFz06+x`F8x5Ds?XSo2OZSZlj>;r}wntOP_$gu0eK zEc|Q&A~22o)eNK5)Wn-7Li-TDz#ZaEEFCt5OZ83mV{7S-$kLz9pA8z{x4heSEZ53t znO}mQdf2H08cuhdmwe1t8dup-|Dfn1V*?@~aFpHtpLXP!^Z-(zhYqD5o~0)2(NF7K z8J(wU?!3=a)lB6CijjY24a(|VQIOuN!j5=~n%ad&&Vky*$)GC?3JzvFM#8dsJ@#Bn zl_bTwsu4{Ye2?vv+R}213l-;2=lMkLjGriMe;)x-d3= z8Nm%c27yM+@5447zEcUc9Xelw!j^|PDko>SNcr$7Or`PX^SUWL*}jlG7`tb_A3lGk zkmw|*ps>H7hG{wJijho}@kEpL*ufhS6|UQ9bO~8&=8n&g?IuvLo|-8hH8`?-<(rYQ zwlCwOjg05_c(YM6DQ8j9`R&rrs&}YmogZ@Y(K2z6iOVNVl?5b$c8L6fa=I_9@B|$bjTA#ovXj>J^19jh?b}Hs zMQXH{)Gbtuq&?6{-p|D8Q?PaX_2Tu>5qgi`x}YrUmA@5?9}&3d8L!I8nvvVec?s+K>*3=5`;8PrP5D4;6V2y3%9WFNMXmfd>evC>hORV&1&4@~Zsd1=Iy zuM6uhpG2gqttS1dGwqi@x4UjfS5KZL z+Egk^Sk5A^6AWd6>x)o#^c|vczUtS}VITU5TrytLLL-ty?hy3p`L_qNwh$#HpZo&N z56N=O3O!)DWBjo2!pyIS!WT?`abfF}=;41pmz{B|9SSxXspiPY{9}!Y#7u+&K6Meb zmJMTRia;JZ0sD1#xN=H0B_ZL=(hUv{3gZcZ^1H*(km9DrDvP^&ne{H~>`A3pd!I@e?zwC~@So5#ur#en!`g3HL0QYP`-xymLtyv>g6-mot%7)%0@ zjnGx}5#2XBi2&_r&oidVL?qCH&c_EvLEiu3(ZF#G^PnK=;yFW(4HGDdsaC>EsC5{G zV#h(sj2cqtTt}81yrk1vbY;0W$t9EIa>g+asNMh(tyQ??i~Zy5lo??#7Nsk7!Rt(wIduYP7B(VnO;b z(HSz96#FAe#dmF>l$2n1;O*U9Uz-2o#V**@<;fZhKuzj;ZTm;rfO}yiL12ML%x~7` z93i$n+7Vf${grZvN0gIn_>}Ojn8Bi!Q&3n1lLn;2r5z-3z^+hh@?kLn$6<3g`aR*& zr6%;5=tlt&!RpQ`pUeK@x}{iLzWMSSi!aCx6nk1p%jaDs5YEvH9!Q zE~49!zp>E6-6`YRH7u84W75(l5d)87{lBT*v7dtmjmk82T2pjI>wt zL)B-;7q@{A0+fUV1#LkPjHrhV5Vgw>4qr5P8ktKl6$C(hP`!oPRfCVn*1}65uSI>u zZ=;#GW5yVR3&V@gZrXi*&#V`qnvxI;9R0AV+#x#eGPw z9$fAgfA;4@_0LDvf4?>z*W}{5<+iPqf&uragPY}Kw{*D-2s^1jq;6n#oLKZki{|h< zY@X6o?D55cD>Ww%@bV#-uwcjDr?ttD#Fo<-05Jbqm~MQz>u5e*uj=7;B( zE&R3AI?=qKaO%8*lrpT#3*&3SYFnYQynwrIFjj`=GB}4?QgvL-fu2%j-%V0SMW$5eerA0PF*4vBx)^N8t@3*6%`&wxQVniFOTN! z$Fn3xNYnRfO$>Xq_j|>Tx((~Kyyk1@I+Q4X`Kx-cOm@DH(kt72cyTRM`?a)i%FQom z;a|Oa+lNXMk1I!{4p86NXUJTE2h>69y8UgiqM|pBBwHy&}^O z)}9pbD(%pr9wGV8f#!0O+NtwaC^ghy+Uf2N$t|QAkqWyfXt$;6lCXQ3!Fc=OWZ-vz zWFD0hPf~a8@S#aU8BepvSmE%j2?gE$d4Cu!_l&3xv1`8W`e?vz`rj+dok0XSber8V zuZp~JqXWR~{?-pTUQi?P(Q(epTl5l~6+d9w>SYytCe~|a=5l2ztUjo(`GL!ps$Ar2 z0}r2NW*gY^am`m_X~1P6>w%whauO4PC$La2UluG(&>@B|9NfP@;4g5-EIsGP6NpCIK^&%w4$DA2^)*8oa^yba*&~b>7fW=Z#Y}HSq;3NA614x9I+dLZ6ov71M_H z2_4C>_bsv#efMH&H|pOt5)&w5hs-wPdlFI!eW0xK=_{w`i^AeO zr_!VNOhT0KiNpks;0L|Y5yvCn(Fp*LqF*mRpY$}|FpPh>Kb$SLrlux+*(N>@ngmSU zZrX8Hn@W|ox;kv#0T?cz?Wa%k`|^5CT6Ia2@HOBQtXm-M;d*?6bFPH;@Vf&y($v_9 zYFr`k{*xz{@0^~-maVQXJa|wA-y0j*YkYzwFtNpe7(cOW8(z!E3 zIG`eU>_Q}t z8y8O92xGlTeNq`!1X5yt5rFO_h6bojh;2d1i4wVR(N02N4AnwF5MSW9z%U|{Sd1^6 zJNKaRU9_?TP$s9g$_W)^WgN%G6C#F;Nl}r6Q}Wd47I5Wgqe=nqp}mQUisHiKY;*VS zI?hsRaQVSmh-WF`@Ubcgn+k3p`fxYIEIQSRR6le^mn^jz4Ck5PH0qqovHh#1VJV>` zFbg=PGx)Dy$#o0NTg)}wupyDzu;ymPWt3c;re#Rb4_bm@L3CVqtuv=V*!3bDl|2uz zg$gd)ppN7<#;%s{CoTO902Q@Mr`%jJ*?P+|Tf;z>or8lG??ce1o;vm9gwtfpUOL&q4&GA+kT(|Mq<1H0u@vkI6~WcW(M#Jbs`_EcVE zry23Zym~fVCTK5SL5k|ab+lf3G-~+)2 zU`<{!&#Z*z1)y~^W2CeXByjxA9b;rNd5K`O5QERnv$PEZewGU)Ij|p(`qlfBbadKi zheR{XN*M4GazilP5Wyu$Pu0=^BjO~ zQHLuH(0zSc)4-OlBdkX zj5*98H#ePHnST%)P#`5ygT+Vgd{bVllXzZ07MT$k6lmVWH6Ox zB8XF|*HTOu!A(Y&?xihaI*L4~nC$qw=?O`OIy%Sa3N@m{#}O$Ifl;PLH8jAzP2#_8 zSK@}9Im47f7ZH<}#;-jpw`4%dqUhHZA-G^-B?j4k_I!G+*ir|p^fUDVC1 zAHf5pdJn=d`mJz#erhmu_jH@(k|n})6=r^LE1gAP;=)8m&Y86MZ1-A@3rx?Zm4a7s zi(D zKJ4et5!=~lxd5DNly2NOKKdFl-{r}=;~V7NPc3VA^8ZLQm=Re*L_LYPMX?4H_^nG7l9oS6X13nETD&$~`C^rBc9em@)NTT*q02;A zDG}!ztc|r8v*1}gAbIr)o9coyCK)C_vflXF_DGCUC*!12#>awFFa5dyC-bYNW>>#^ zcdR6V^P1R^%@Ek6)a4on82c3QD>9lY4Q86)! zlpxB=Myi9*f(H+mYc4BVJ8qr=qepk{9QdTm`Ql@%k>~it%05? zqN|;vW^W7Z{PpMVK%+I5+O4+?Q*lLRK)1wU8(SefZkmVK3dhgQ3|mkT#)cHzy4Rkn zyY{M=%%HgJ3LL0~v=z*cxYYPVv5((xNxSoK^E=735K8MQ9~3{lv6y(?0r0GP3mAgm zoh>_d#HU;0e3UsoGrL~lh5G3}PixH_w}wprF?iDX6_ijpJGO5LSrK{HO0CRgnuVY;>>>(5B3jle7E#U_W+s zwyUhS&SuRI8Y=Cc>oZFHvvR(WczI=cta%=eeoh+97I#blF0F0$mpD*KaX`VBtcT_0 zW46L6Q+oI5Gdes{G-G4WepFA+eMU@pc=~LDM_YsKxC;RgBd*cMj^C)#?>vKH9!iHT z8Sf%S%r;|P;mye5wK?M@N!Tx0E5dg6al1KNFPk2YKDfrr{j>q$tVxttYSSI{Y4Z`b?wX}a8DN9Um(q0e)A zuBcsb%m&w-gAxb#&o!H2ana!G=&5&oCQdAS=g@yoa8lFgyRHk)UJ84bd*R@)*7Y&6 zynC_^wHXiE{JRzO{Z}o(@4s8m1sqK}A9d*xIvxg#D<2?@h=>-hG1WQ^#l5dp!Wdt3 zd!Hq3X;GG{aoaa|AEQ_6v$sA=x%IP*bp0>WXbTmfZoXuC&DpZ$3rA=~<$0;=nccoc zi9u%KyV^%WLSGzifJ1?9Aiw$x_V_2}BFt9S4(wlWyulXAA3Y*&zLNS@YCD)hW4{xZ z$B2dbI~ZTqFAzO8RF%JRR^kr~#W!o7#s>$9_qRoE)Qt-kJi>gYscj&I4LGQx_*tTa z3XCxJke23oJy({37={K+F!?p0XaWu=B+)oXZ03<+)0e0YLJ1_QL0!NeEHHM^(wL3e z=9gaD$qXi43i%30`byGivh|ou?B>@#{iCG(8hd+OZIrbw+-e>VVTdfRI#5gYTZ)zRzCUgdxB^1{`quULsD;0c)CCrRWcM} zd>U8^A3uJCYM3^3;hHsyr6)cl4da+U*thGoO$$CM;a=osCnJyWJT52Qt1K_~n<{2$ zAj%|tk`s$778Ztl%6|Ilp{iJvu}Q0|UnZ)OBdj6t0u~vtu$=T<;`yV$au`w(xShQR zn8i)z3;dJktZC>mng+^4>`030nqhyB968dS{~FAnSa{^HYZUgTbGN z4fB`O+WXrrW$SKiqkYiH5&gpuZ8lyM)JYV%1Y*XTCn9_{*gVFnDn0{nPC=ovZa=fj8_5;n8S%PF<8)*9Pj!6`lF!dBbxF}R4q`%= zI=A#kCB~QQ8BrkAB1o}GY`_QfAe2FZAq)>CEiA8*;#}JBDatS2K0Rki4KjPmA(E&F z+^GNXLCDUIIC~5aCC>rnH!6N#>KR>lKU9W z?%{PvsbWYT%i4BB*^4>ljsJ+W1j@up?Z&R}YAszdJUZIx3tN!p$$5k37+QPrG%yxZ zSye?{^W14Wpd)n5W}$~*=oGs!Ar+i^P9yN6ri;y_f~tYmVlx?5z>dQ|sjJw`3DQUQ z&N1AjU>sCX^Ib3Qu%twf9<<5`iqdDuL9S)K9`UGp3vNHddsx_#nMt=+d!yjy8g*iO zT4sYW1g)`Mq_Az-r>_u3?iKUtnzm$IPg$pEY_2R->2>O^VTnsxx0b8*j^7LKEJ|Bp zo8Vkh3x?-YVt?uDcT!uuTjsi+K5m7-DOgQo;A5qj%2@*F&?)(_NvJ|`c4JPt+_O=tOL@-509~xcHl~pL9}n zP}?N+{-ts*Wo3uWiUV*6;CW*@T?XW7pwZuNUBvenHmy)OagKwMX%s}M z7cOj^!B8!@d+i^0+?>XryYadpUU9u@JaRxvmE`0FCKEY<7(rru7M1l-?c&IL_J7 zQ3z-O1(5M&kZv`;XZ@kuZ=og#Y&c}_#6-g?SnxoNja}=>_@Zcr;ci_Iyu-z2f|Hqq zY2e1SVGT+|f$?D$+I9S*SaS~3-Uc1!dINUDVIlDOh~EgB=@Td5FR;-BT$R+<9&Vy6 zRj=EvP0GsJ8l@QsQjv#-)qo)HX$!bll@Q-=j6zSJemTip0ax+me>`6=ep=gKENaRi z?O|>68_^Cp~V8-dW+(-4c2R??dC;Ap00`z@!bQQZI5|)u8VX$TW1#@IHn%Q&4Q)y7hKjK8!mxt-ACPhB&ukwS?M~+jGmi2fNgTq@*E}?M)GT1L%Nh z18QO#jMiv~l$2ti(O>h|fqp|aG69|tgzf+eNK&6BcJ%1c82TZI_-pzOwSaqwWs#4c zJ6Df*X;Hvdw10oZ(X}9jv&Db@_<`n2MM@&WN_XWgZ!Q|p8$yX^&z^yH;ZxepYoCdS zFv}hxByZ*h^RhF<8H zM5I^^J9R1|JA*BA(_=ExZ`vV}Cv?Q&(ZhAA(2p^@c=K)0ffOpQYHK=2%#Fo}sf-c{ zSvaUN_LUc*bEuJ2ZkHx4MPJKHq6Z=0OFtnl4q8+PUmuWCC?aY7gT#yfBy`?p#fq_k zM&Qf+^kISb?b}B|4XTQZbENTI?ctkvc6exSdu4++VG%{OV}WOeH`pk(cGaguFRw1a zdDKi_T3ULGi<7*iAb#uS%}(ntP|`7xkhjLoHKd@XA@NBFT>E+U7*N1Ut*Y?(Z zjS>SF;Y(Z|nLhmbox67hOzp?Wm-&CrKW%Bpl`DadopgmvDc@iD^}(JAzum%hw6&!q zx-LvaKoS3fa!gXcD+-9OG~$5oIQ5Q`P`)u z=)!wRYG;ufsl@Gb;8r7wk75yU@h*D}*JX7`=I zCuo|<{p{oG6|cJK#nt4T96st^cniid5Pnf<7nEbNE^77Zo65OSs2TAcL5<)BB6Xl4 zBx1yldv9IX+bHTFU2>fEPnbOU_}o~*?0V}LH|<#S=LM78iRqdfdsc0`x^yox4vUJS zsvZq@(g?e0hl;k=TrdSMuxAsYxBL+$*0$ya8|VO?zd3`)OrQQM)G^*zFa4?)!b7G){Gr)co>$Pc6QK*qLl)zqH=J@WTE-8 zD;_Z*%5ZCN%7_Wx{LSEv>G=M2uZ#CIO!oa!&`ltTy?cT=tA& zHR1dD9L&fpPMdB@SbC7$d#aH(1KTD%l99!?Y_i>TzU{m>>bz7LOAt)Em6+FQBgs*@JRn&P>%S&tAz;8>U;e1tIcN~Ul@;k_Q0FabN%aH6_D}Zfdh9EJSKgFhPpm#phY`t6*Z0jUAi8& zlONU*;!*G)06mqyeLx$A$O!6q+;0!)%Lf_>tW6N`Lw|__CDYgNDFOoe2IsLYz@&bD zzLA*-z5tC^JDPv|+4y!=OUPe{N9+-hvG4=|yUls8NhCs|&w7)dx{{g&fO<=YRoka3 zn*kH4o4}-H{Rc@&S#SlWBI9Ob7-@VN$qGnRbUOz(B@k#E=pdmWaT1C`y$84?fT8tB!mxct5ub3H39@UaK~b)eYn8PlB|EzUnlU3oCSAig z2r7#)kz5mx4@prF<=|$d^MD(yQD2twv9O?(kbCmtE@Wl>VsFKJ6tbg$@prTyfT?MtIfYbz^ntx<TCDR;@EX#;0s;zvxtn6= zvTGs;@Rszt>BcJL!64iQywyGDLOx_H?&=-G1`L?A_JP#zbZW*MH*U<0(S|Hg36$%NEmGs(go#%6b1iB$Pzod3Ah$f!Uiww(5snco;Z2*=x*!Z zH@Ts5Ai(g}2!GBgViM)0q@;)nnh`{HMGxa3!~?Rnq_k55u*^mea2n=qyp${1FR72wzlO%3j)ScZ2|zxF1}ITw%g^%p&GZQIygDzUB3s}nv|nvP zJOQxT^y^6}R_+T=YX-LNKq0D$!igsAj$%aN*aZhtFX)#fx>V%xjAZIPW)WZIfl ze}Ti~V1JotF;~*S!Qot1)-FOcTN1;=heZ~2)Wt_i>a(L$SIXLsS5aZTX76p&A{W_3 z69YI@Bsn>+?%av(Sh~(ZPW)^}#!fsdek@)uHnZ0-t!6wYve!kB@{TNfxUw!hIlmw^ zbu0ghKrSr}nFVLW&L53Yetz>X84L|&`WjJn;pWZyQIb=|!xwfSd4hQ-VWFpl1QBPO z(0i>XC)^CbGB3wjm^#Ri$o_s=vd1G5L zPAlfo4!wB&+P1CJZ+gbFXKx|n;WPXZ^E}DR>*4D`u}gueBkl?(*Az$R%Q@nCh4;Q=8>M}q060uDBVfisWR1T~*B+Q~#M zC^0b^OdI(~Dj2Kl>b7&P{(%A5Zxc%mnj8{q#9<0}dX{ z^;p!J(&g!^S2_5uTKQ5>et40da_yS5{JZ*kB*3N?76w6UXgg6Eum?-(qgY}gXMYUq zxM4Ho9A22p%C&+mo0F5GxB|0nH|^}xytMpVu3Ww>(Wj3v6usF{1I;gELtN~7+dPQZ zBS*MNpmQ)!MMX{QE%h?3<$WV-)0uI?+~1lHD0z;PT0$aob5*x1)9~1r)Ta;9tSB#c zuPuzC8M5EB$xz&E{f5lkVH^DiVHT0SG0x`os*(m>0icXtzs%a&-?nz&h=6(F&sWmp z5ACBgdh|N300UPeHkTlJWmX&cJ^^>!6eI++^FfL%w+Lm+a~9_)>?!)#r9C|b!PoA! zIZFHGI8zdr&Y|k&sKwbk*8EV&QAwZ-EyQ88R5K;PNa>7ZQ%vgCZ-z0xHj}E7*`QC( zIIX^|`7}U`0OSJ&O1uupQPY`Yb7Lvk0dQ^}ph{fSWf8XY*Cb(D0UkMDKp%K_95M7J zj_0jO5mQ6%@Dm|9&L6yGBI4x^qR480VG8gx-eUD41#c`5k2B2<<5FEckYPJXvAu35 zplC}YI1Ov|Wc@ZY}Zv;FRXY%aHr>|%j+gL(f!;u~!YjW>A zCNgKq5~jBNC6N{(I(h2my3O|2+W~DSAr*#eyP+YWU2cH6Xm^a2O(h-l^G~V~kfPkc z{_+OStE`*LSM6~gUE$X?CA6j})xsm4!HE*h&l{bc+t|pMe-0#; z^(t2!29yH|IRdgqKsa7g$z57*rX+h4unKn$tohq+^ub7JdDUw@j|M#capH7+>6uUIW}6l} z{ATbf!M4{NakESQjEG=(_GpbdwMW1RJzh!}<&7>n?B{nSr)Yka_nGxwsA}x7bLIf2 zcfGa3kXQfqVP_p7#?ABb+;!EefDm841UJ5o-kkgYMD%bb$DKRpfUrye$wz-%?9s<} zB-QxR)a>kG0Z!io96s8F8HH$>4jDG0nWiow07(L!*PIFlS~_N4i1cZt&)$#Y#;sdu zGqy99z{WQ0b^T!hS*zcr+aC64UDA%6e)@2$04Eu{e_l>c-%)VCq-^gGgB#UcR9GOI zR=l~Zb}TX-k+`YP^#Q0aTO1rqmLx@tds?>6{p_ln4exe}%}d5Yut^loFGKz##D_|W zB!*`*L89kcd(1o$0#69DyFD^9m5iaLre%1(>dv6-aj+_gMtOPkXdjkaeNYZ3N&6M* zcM^_JKvWH%0bs}!Jg&?5e*Y@*i)NWpR&#FFuwK2^amjLW4!+%>+jd;g!Nw$hn-*O zhlWZ@HgX;T&uI6TmXc~VSbb5PR9XnT#@Jo7o0L4w!P8L2leID;8R%F@%zS+bDWR2`mLl>lLSz5M;C1z zbbZgStJJ2tJBgadPnzv(mN=4?BO~;NkI3hQI62<-XibJH*!;bF-P_WqA2p2MwV=eZ ztM=FZatDEx_-*(TX}{FLVw&8OH#fWZr!da^hp0}hdeJxS=}hZ?W4CkOe*TP;i2i;# z!7)?EouhkpkfL!AMX!Zk+=UBBB?`dy>;~fbo*FDME-di0S(+8FXSL2FW%n&Zj&oS=x2-w@~g#R%Yfm+x3kO zJDYU!=|dqMz!C6HV9bLvI%3vV@Ymz{)g{%ZIWO6!Ba}+ok}h1x`Ntn!$gedY6EUYK z1YHrG3pEKOeylmp0UqYonIKCv*1Ns$3~ZR%2WOoLXVR}NB4 zY~TA8z*|;YdN)oN?589YpdS-R=@Z!Jk3}57MEaa)22=2}?I(YnD>Yz%*QDaQW`3;l zF7N4JKmf%JfDG`k=GK%$^$63!Yjdz0#z{63^NatPwKgocbOo1F-ooB5c}iewWovJ5 zNcQrfVIb~@abt<8LY&BECyZK6s2UMaZyxz3sY*NwOMCdG@hh&*R|sU&_!}K~{P$8* z1ohSz?eRbZ@GA@OHC8S9yj_kkw2=8ou6}Elw)oMS9FDvId zDnqqFe#Su$3kvAD>f??7Q!<{pGG_B2iAK<^*1UW7riW0@WnZr6E33LBdX z`H#EU3>=?7HWRs<@9hoF&ckYxI=h`uf%n36L3l{15Wo{ntdo?M57n=wTE~0#?E71G zlV$x2YT(M7U$2cirkGdrbyR=jl%~(dfr^AQZyPVsSE+K5n12AMY{0$ZXAcB2dN;8p zn}fV3rC+&{Xd4c00)R1+TOdmeu6bh2VWy)LjlT`GE=lkN;Mjb-&b)hXE49J4vSpUu zP)5~QhOYuNx44&{(%M{Z%H%B#I;f{pS8_L%eN{$mI!?8sbZThK+vneB5he>6{N%~m zs=mh*jrYws(-NZZf7?+tsccY#3Z5b*9Zcl;uI_vD-F@BVk$ z)c+2#DSnb)_5bp>weDkP6SEsTls|m)99*D2eMXzuyzHgI8*V))No5RBF74wQ1tdQ4p zdfHYL?YQ40Lp5mEPQSLpfai*Jz2x%WNE!v|7R+Y(JPw6`<6^m8U)S__C9 zoiW(G=SkYz-(@%2i8bB}&2{8RFSU^Acu_Mr!tTfhSc2wj-dkQoJc_8o&jQ04MR){K zeMR{v9)Ic*t@rD~HDnV_J9D z=j^36HdNB>gd*K8FUQI62Rr}9Kjt^BH24Mz{q*e-@YB1o&v7{;DAnN2Hb1<0^{Qaj z4^K-Oq=6cr;esgB9~ARcW{8$f-dVMWt%i9G7Km8lq*Mx^0|LsQ_vno;;Zoxyo;n|)j{jmt%Fa(jT}IL zVuz7nA<{!!o~r~1mtob;C0P_@3PcXg*I(=sb6Yf$R*$K?N9gT6(s9=jyCtTiXN^lp zSyD>(0)L2m%Z=80A$YFkO5C+&oJqu=aA@9Im&!CP$0c_)!ajthS$1gee&#jefpZ{j zxEhHD%wb_QL&H(EG1f@271u+0g;D(v%^y7k4-I7A1o5;3;xcSMcrfGa$Af|x+*l}S zK*$m;9!LmR7$qBZq`tjSb2(w2qoAt#f$JnN$Em5)G38+DPvrzf)=-QUsh5G-_~m6d zd(oX#Z{fu8zkLJ-9$kQ?Dm3a1o)f;OMT(3ZpkSv30-mc;6cl4E-Tp~@h;Pk5(1)t zM(ICTxRUy?3&N4r)D)_|b}p^*z%f_q;}@5v$_yDoP)G$d6v}xTr26#>Hm6F<$aL-A zJy_9L@^7$1^wm5ja#AjxT{gdI1 zYT^YY2kD?eqvp|wb?MRtHi;S0zZnVz!386q5IUcE4DUiB{#^F{HZ(QGw*mM$v&_~p zNx}P?)hBowrl1i1*MOJ}laJZ9fDKW|gtWHad}Kahg74+KAZ<9d_o(O4KHcR@=-5pn zKr0ozVGf^_mhxQYwAPRHE~LN)$=d7#4Z*NAIYxvlXe-^vyQ1Ojy(2PSlFPHUJ414F znSf4(dTNRu2qhaFof#+#c|!;(_-rc~gK~7-C9w9U>`1n+nLOA8%BMeT7VoR1n5qnn zhQiwA9_yuyk-NwRW9|l)7 zC>xan4+2smCrTe_56OS)LYkdEGKJ3ZlL2nh(%v|p&a`)MIP0J+CDBh`^P(A(LBCod zp51U)W9sHI8-gHgw$R$x9drkTy+yU2n<69#(YrwQcI`Zqh6W!BKHRjSN0DlQ1%ZPe zJy90B7|o~44ZW#T2S?7Sy&P8`9FJ95NPcW_%kGeVR0;acTg6xggvUZteEaexbI&i0 z6S~4A`=oVi)~(z4?BdKQQ&2A`19lr+Tqeuv7W&<(jL+#2law@1EriGe!C7o^&`mo^ zDu1Vv3e`4)*X&?`U6ON+jm;t-?jP{W+|29}vx!0+5gIxRg$u^?4R>9Xb%!Xcsyf-* zW9D{ePbFi=a}|R)ff!3s3)uxBoMCk#KeI}!;mJAPQYa9V;fOu1h!*L%;#VvZ5vyBV zFu{pdf$pNm{vVZo;}e=PX%b`N;^?>`lz?M?|K9CwN+sLw$^<&IaNuKcaqklaLUrS- z>xU#y(H1NeVBUeU{q)&@#G{z?_m&KMbo9uP4@t^a6lREE|9lB1fjsb=Kh)i0;2PJb zBflJ;v8vIbqV3>6ZZ-qXe(_?6A*!Kmbx%f(4xUCp4sV5uj!&oH{k|YFAi|~Bl8`0i z#*Y2ZD{+Lg^;qFPWW|cqb^gqDhJ=*S^n+k%4n6AY+kK`ar_J6lo;33fnh zIjBX^rLKpGXa3CYPnWAcVS>@Zg?DA(;L!n$?|+C0zyL|OZb7TVv|`bKZu4TcCUMSg zNBs{4(DA!Qj{~61^G-PG zQ4D=YRisDOl}w1>-pH+s(DR7+(?BCHNql{-gZd&IF|1-9O{xuM0j%R8oz5#MGbl6oVyk(v&G3HrjJXtRAu-Ekmz(Llc%LkJE!v3Lqpj&Sb93E zdo##~Oxi-l+1}pmZXef;w8)T92cg6{dL~1e#`hJ8>3AMhB+aw`BaDjfF=@ zxRn~|IPT*Iq0~(2wqNdyNe|B@fCF-B^|St+DmE(e`9(JJy_7z4Rw2?CrWGIQv6RtR zK=#zHtrL&JFOslrS1Jz51dCPf?yZAucW?e!K4s6iu82!s2k+fqO?6JScvKQ8A*0hT z)<^E~k*u#-Hy9Y6-8oxTmfOiFgpewzl|O>iZpB+boVv!R%$?Z4yci@MJ2`l&W!|WIt zxNiFQLeEAeNJYatg|Q?$`ord0uX?KkLoKcD!%hVIFC^fOcQSbN10vWgFxK8 zgk)B{cgVf08i@>%>5=)THO=HCg?67ES91>s7^TwCiK`4|%n%Jvg(e+Jd%|5D4z}}^ z5U^o7?j_u+{QL%pD!@4RjUz?v8qb`r;uQJRN$@+QhK`&?v{Xf|?#&uB|M=e2lK?2G zF9Zz%H?iLLG*!<2Jtic-jrGetXnM8*znZW|3+K-VRG%#COfLdE_9AD`bp87X#K>+_ z2!vat8>3K-)bq%xspMu&f>=i-7#|mRE`Czz!<3v>2kKMtDE8uT6kEY2x`;}}qu3cY zJ-^&l-nH?~%;5p)1Z8@gf-?fAuz}i7E=NKJD|s?B^pK<$*=C$O5SF;(imu9vQpRwV zs0J%gy>vLihOm$d;^&HL?TJ>IDM?GoxvkZnPRr2@N{s` z$bx%a%}3tmo})kh@fqmPsy9f<@BrAGTeolb(^oV`okeBL=&+84l*oPk+O>k6D}_c& z{o^xO-@o%Cdf29{STSTFdIsJu&k=n$k6GN~uFy9$J_9B0(8xJDI3z&h>(hg? zZiE($FO##GGrhX`19siC1HP%^9LC18M8PPC6yZv`Pxrm~H*c;)woSwUIZiApb#-PS zYTmyWKJt2L9d}no){GQoX;W#@@HBX{(PDyRHy3G|R7R$d2&z!R-$ZlQp@V$!#N6td z8pBv|vCixm8#*w;N~n!(f773=hM+x5vY?T0v7t?xICW}#e{7?Lge}254Yw<;8O^H8 zhULUBmXnkeo4I%ceF)l_0~<%V7 z)(n#*NSL@Hdn~Tm2gIWoWNU7AMflEaK8O6)2gk?A+9LKYzv{fg(9oB`@~c;M!6OX} zkkpp4IesU;?~Qf}SJQH;aDI+!1!S3-~2^qSAQ z2d7f}7cbLZrN43qOopVRct>d4Bol&T=|t3y$gIpJZUc?shS5Ha(x*JNXADP6Fu|A| z^p3c;81uSGPbEBS;_w#YFCs7&kAm@~f*z{rLiFmkSJ!va2=Nq&M^RENqZz+4OaJ=U9_9vayOs2`O@PTOdX9#_C|RaD-s4ipG!sn&@@= zt(>>}Xq?CWmxEa&Qs2fSry0Sd6qZfDUz5qp)Tg9AJ@`)okZ2SVid{dG7A!-BLFPHwku1?40v3-3ZuYL1#bIV~=(TiLz*{G_-zpUiK@ z74wi#5JFgLctTVdvM>Bi>gFn;0fSM%C@Ul%!iJ2!GZ9g-vDG-fKTqFeJ9FkurrS`P zVQRMU&%ie|ojYqTe#He#Rhz3$G7&{ylC6Z&wc!BIb`m-#x{WY96N?g>y{S&m80D42 zHK~6d)vEYXgWP!=anPnkw1GY5YtNqSq@=O>usxs;%?}^eeBBjSHKtk!W;A~ssTVMQ z2K~T#js!5l9{`#B_DqLTl>_=kj;lIO0Cb`5Ht(2{Xd4%*z4HsrAc;`^zrvBl-dTlU z-^ab)h$$~XsixN@ccf0tE$vtB-(p+azJdL(D|g;EBP2UyPBi40>hiQ&#QEY;NXh9gsJu5qPBZRn z@f#l`Cygu!aR4)v4#NCt9qu!KVoU^!St=Tx@iQdF_HFXim^xJtR}aDHIb5sMaaBPk zfQeb^O87xKCS3bHZFP*IivXtvt6I8nzT=L?Avg}J2VRJK-N6#+r;q&Ic)^0jH#*6_ zz#)&ty8YA3LmiN^M~)uN+4cRx(PRmmc{pBNxw81iTHSy}6QFake5txFjhxfkI{CHH zAxX3f!W=>UDt14{DCN!fhm81ST~z1lEg4x52~N5YB;$B?_8zEu{rkDOcAVn~WW=NB zA5nqBCy(?-tVF6a$J=u12TRKzMTR5Z_LSsiE-*1sGA7+rVeD8(v?*>g#b%-e`F`q| zV+A=A=nlX1dSp2p{oX;G>n_Q|&b$fNUm*Jm9-3h!gS zzV}eo;-oV9SnnRW9TP9!z9{mnnV)EJ!SYfiPb4T@RB;`9i3~C`eW6&Z*zwvLJcN5E z)9Wq`A~5n`L8$bUJvn__!xC(S*QE+s2K;|dc??=I@i^q}Liimr_`)X|bK(K=SK4P( z85d(?@365_)gbCdW3Mw{SF)hHhG*Xeuui!E0HZr)%E0jpqf9N9Ea8#1tvaryr`JLD z4ae!M-MfDazn5@G5E6<2x*bZgh|G40+^vn;J}Wzk3Krg5X?f)KTg*(bc69U}5v0g^ zrvbYwH!wJld}$=4PyRA2Z|Ewn5$3#V6{+Q`TOQUQnk>7Z?fpV0rfS?=k3U*BR!YJl z^E@&pfGr}ufHd#3f)9+6Dd{OYY`^lA8Knod&<1|DSgnc z2Uk?oR$Tq5pU6gj!aZ54@Bg6A{-4L;8vh^W-UFQL{_h+9lB7^VB?=)cD>Y^Jg;x(ef{s}e(vYG$8{X{b=<$>JkOjm ze&6-^yx*_)YdH9)#8N(?g_^W_+pJmo7cDA+jwihWq z9x(8L3(TxXr)%syy(I#1js&Sd0h$bHsZ8ZO5kM*Rq8mr>0X<3~d>!2-I!N!5psS!@HnfIQmL2IyC85A~*CqQ|7eF~0} z0@Bh8=zUOzKLq(0@-@k;R)1V^QvjC6Q2pzkXq1PTy;N~vtg#aV6KqK|@t8r9Iw`E( z&;#KPIEniOxw^{3n6rRAg<;csqn)@5{Y)X3;L&(~Eefk7xTA~E9HwSM=_8-nNN<`y>a6ImMqI5AsaF^$)MJ2fz5uaJ1GJ3l)sjPcr70^Q$io;8z3k`t~U z^s+(PL*4`*4dt(1JddE#U^apSuHKFWoyblU6BzrU^9Q{JPO5e!jg->wX@y(bvF9lj zITFIc=fL%bOD@m~oGHwi)@H99xe-{k9FkWOy$sE5Ms` zDi-+=>E`5=xQ|606O`P)9|JtOh`Pr5`cX-8x&@3FNaQlJBvlp{WND~p@;ZN@pTL#= z3%)QY%MWFpLM;HO2w1f=CyF6mQFnbqJfaa1Oyte66W(MFf}f#i`%9W;-&Hf{ipvb# zWy=N-D6zEz)$-0-Pc$1tdWA5cm?ktYv_KfU4zKH1Kq<4|ssJ zz!chB*pkgQq9~pW{EGBSZEbW~dF@l6t)a#S7x2QbiJfv@&geg}MlaW3k4I&33Y`=V z7XO6~ccF}wSzr+`EB7vd*D#(H^gy8Av|Xwu$^>DdHen7AMupRFNH=s;6%BxmVP5y? zQ!(7v4jf>!IOPnw%k(tBE^z12lRih8BI$ys9KamI@z{NfafZoCJ)>oSUCqm zEV&=XW`L+Czk#2K^)NI6EG3`~xFlf3Lh&=PT}FukjXad5>VKy)BF7=XLL?b*@Zv@s zD>``8Z+(4zC|iKs;D*4u1ajXc;Cz4J#E(W2MJpJ^Xw!TU_JLm_a{s2GK0N+P+|&}Q zLASTGd;-EQDDSDMGM?i*B=4<_rTH=zJCiu1dR}j$6Q-0X1abDfvEqO?gcVTupPF0V z4Vp+buDf6nqBlANw?J?Z+DsNmBn^cW_K7j`I24_@@o;%kYs;{<;@yGkh!=1TVIck~ zq|zKSSgii=rvOq<#=)p)PCTzJipE3>qyqS-96D5u)CWxY5QDXWiZWjR!M%GRiJv&J z6^NFuu8kN=IWPRHpaPP8j0mk$m~#yb)C^5y`~yn=rAr4wRbyn_lJPNSo&fF9m4RaV zSJ#0e7;{rVK3KqE%!lbIiffScac#ib4k@$~dt*RMm7Zje=W|Gpt? zvoPQQEQjUlb= zK0tH^#Q1n@e-kaREJ-l$LN)MFOIJ&)+VjE8bKCi2P=yVW9h}3{Re&)FV1mj5w{06; z0QN7S66oFk)rr0M$A=J=I_6r4S-}e@pG+MBvg9hG5f1nZn;F_=DkU_Q!263}H>8`= z|IkUE34&fHIyeY^%V$JoB9QistY=`7bwA;Xc8L3dIYzCVXiyt{b?7~Td z%m|}OP$p3RPaHcC!0F6!`_-u&_3$4lhg7!=Vtft@TNoZfF~%8$U?HH97^K2`6GaUv zMMVSp=@SbFM;OCzzaO73nlag~teg1N$P>Y&T)dZ)L0@I^VET>yPd=Iy1e_Ria5O9$ z?{aWVJNYZ^LM>v-{i1>nl;^bKR$OWyh zVd498&qeWzQ#_6fjc$!h@%o^)&I2p8D0ZeGYEHReXMo>Lv1|m~m|b1514!Xs2dfbT z7Kj6>sHrh%M5}>4*3^6%n^rQvX2uE7#9_bOU0ch?&0Rh93@aA_(K|V%!tztx^Ytz! zR~|rOAZP;CnxEv1odEfaXmh**==(pd*2bAi*Y{dF_44L*_Dt>EUfdZCas}`Frre6; z*CsI!x|E(>1bAV{&uo)d0(>5zDK0*b24oWDs3M@cOZ!Mk96o}RtD~hw4o<-^#Fd0O z0J#qH(gJPP;f=uX5gHy{-P`*7Fs|OmLWh_=faf>?)c&Lmx1}*!vr<%zLs8#HX1&J; z(X!G6WZ$ZgV!!%vY?iJXhMRK3I>yhxy?bqOad1n+p`Hy$mN}uXU-fv!H5BQie0%zP}|zrH4LqTiS^<3jbQianX2;u+a%Z0A5^>MSpok0L?$V!*C)%C=n7A#Cf@Z zgI>7PixnhNP1kzi@lzJ=kAOD7lfkueJ1r&DK>iF6k+Ga$ey~%)#|tcewBixLSoZL% zv3g@oMWq8?pc-UEPGIOJ`4lx|9%*%h1AxC09~6f?d1)7fmLZwFn+8xJTbR1_9^ zkR#BIsHp&VK2A(Ljg=fGuu}+DBaJscRr*M@UtCX^8Mr3W==E5L2^mK%W0(F?EXT(; zg!9$5D8TuNi|YmTmQCUb)=4Z0*d_r#MLA}%NuwtKQlJ1v3xGJ> z6iz&gkc`l8Y^bZ-3)dZLI(2n*=L;8hNIHPX(FMo=osakYxV&W*F(%W1#R(%PR5s|7 z0$+-`4yXsde9!5d;WG9$FdzVdJsFDff2qz*Hg32(ggZ)%(P2ErBpGL8kAMJLqnsJD zmc*}9Q;6=Q^hf)@BA}tUpmi0XtqCM`AZwzSJ}(thlJuOo1J6AmyjWuaa-K>a?7Uc@={g?5SV0<0v3(qEr~$p_e#pR5N+B*TGV=8nn4w}fMgfi&?pU|P zm+hd3m5iB_X85pp^!=2v6anw*%7t&VaEqPc+5KtKPz~L{sNTxxb=0LSbo3&;Sc~A; z|IuOWN-Hm|=?6I{`j)_roHWWjjP?ax-;2I)rlDd!+-dd%m}98w>A=0mVM8d!!fLyv z$p4wkJNai6p`P1vI|ZYY?W0emeGDs`WXKgQT^*&t$v(GcMP-|^u_`uI<25C>YiA(_^l41qO|0%3T&~fDN}iiwQwoB(xi)V zf$1bo!FJ@UHxC_UJ{;~9eN+DsU3ET!Q^>E@>hDcLh$FSvh!lloWpy6cr-J2btArAR-iuu{^6o}axF8UNND9_wt2}Fh#7n4Qbk_T-RqO>*2JcajnfoW7 z8rTEhUEWi43G9@1PWY`b*=lPBMc0VkdTD8Ce1f03tK9YP$%#(Z;cbm@TC1!F%XpR6 z{Lg8x@l(%n(op`nN7Gp&rtPRb+W+WG4DNLdj#5Aa5Il~>3>-Oxltwr)E7L3|eJZh) zftw4S2*_bS6?LgGA%!wo0G91_{df{L?vS>ur3TUAS7%;|(pLx}|Gc6Vbq+I$CIdS$ zF9Cw-R!f?q0OZdxt~5vm7t_@0~cican>aI~$ZMlAyo33V`dq3E_R z!A}nO?-s&Zyc1D&moYg(vyXrQY&M`@e&1s#7>UDzlG)*X7)T6bumnMm2rUb!AU_v8 zKzDn1rkPA0LKlwi zfLjoUbP1Tw7}TL^D+R;U-25_HXRSU-UoRjcCesQb4OM?yzehMFIh zBc8ARqUjG>qNu8YNz)VHu8}iIW8;g^frhHCA(I194rr>YV?LOVp^>&W`K{HLPpKxh ze0YxX9sh>~p~#s*l9%_5tN^eC8Um#pjK25oJ(6Vbx~3-Gv}oKahRl!Jdud}e$bN85 z{fc+`<;xc!6gl_6_$6gTSj{nj1=%X(#tlk>Jq){MFZjUCO-(;RwqHO!Su(2yE+*`6DS~HOas{}SVuSv5QW!m=|T|?4UvNFJGc(sM^f`o+%uC^KQN$6 z(S8{I_%S^}W{9FUg+YSaUu9k2(9k+!L+~kFd$8Y+15ks0(GxsVbXbbhBM+OtgFFLj zL3m(dLPD{A{ynfyUriZP90WO7GwGXx!_3*K&38}k6lnM?a{FG^1BdSme8D_VDrqh1 zON+Rwj~~1$Gx^+~mLbr=q`kRRiO)uhj{3>De||mkfmrQ!m-Z=*^5JeoqslN z+N6lH2|g>}p@!F0*c$MCZc7U;;XF74;=p>!%H+a%(A^0!h7eC&tRj4CsLgTU=n7Gr zITo0N^ME5ZhtVnu%y!o*P^NKriKBH#$OZZ-0ByI}<)g>?MbOldLqBM1*Ap;`!ML@j zo5a@MgmF}YV4(JAhW`d0uKUQDf)=?gydU*Gl+^AdDI((+xGYX9Q!QPAT`xAXFKu}l zp0U_9W3rDB+Q>-nk$Bp#wWs|-<&Ry9Iq#icyqeoTxY?)kkn58gui_d@f$anJajDF@ znwgG16VFA$ts^H7=6rRxP~uxRIqX*OQMLV{p3peYbE(|c%pT8^WJ)GlA8cA2g&Mg3 zSVN&K+(2NiUkqY0=J~u~Pwju_H7l^82m?t3_P|@2m|DYs1H^oN$_33tzjw4>$#*iu z8)|t-)qR78651_`V$WdrgX01i6cm>D5Zr@!{tW~QJk8b_?6f7-x7p?Eo48d~RG>~a z&FWa=UuXThR&m7zZ~*9u8a#|qXTX-jOC$UOpoIDP{j8yQjsQa;Qu%=jS7(LqCG)U!^G90U72p#podJk$x|wSxMjU*jgW%V*;DN2NlAZ+tH^8u*9x7Z$y5#Xm?ufaCUF(yW4;iBU$|au zcS7MF)m_)iQ#+%xhQ=#?2z$*Md`{iKO?c4=97&rMlMlKV^djphe?ryKPcyySw?*HX zqS;4#{%M;_ifR}qC%W|W(hFFOX2T-u zV|zRJkrz>U3a2Z|%6fxZuhTwl8>LhRsvzkHnJB-lfVy;62ndY|*Aaw55)4#dM@MDh zbOY=VI!fS;QD@k8pzy^$)2|%B$*cRw4kel9x9{S(;g>M%^u7hzv?bpShwdA%T;^1JIY7y zCEbN*37*7%QtVN#gDsiY>2(wDqv0pqao^a!1lqt7)hx6vx-6~S^GNb_%IF}2W#10F zxu|Jx=}9NY2SMV2i}UAG9&p9Z_m#E`GVYI09sS|kiF+pc?V*1SVN(!o#Bq@Mfg zrT4exzG)VWnCRT}&|(>=7i|+);L44;HE;aRcMsi-3%6)jzwCcoqnvu%C8;iJQJ z)f+d0OeyYJgwu=L*t=X|@7|pJd}adBAXe0+2GL6Ab=X7$5tN264BlpL2izC^89jA1 zFx(n>kdMuMCJ*Nr`M@*@S!Y^oSR88y_ZGbx2ds>qA1P3!P{0%Xk@b)>HT<3fzWi9m z4Fc8_EbUlUKRg94s9|5z) z^TH?380#>)12{OrSqwd`C$_e6Id*xQxe;T`zmQKPWM1Y)(!((Omvn5$T2-vri)IPf zZIlEf4OP!4OQ4ZOyutk=BLWe1Aemtv0mYhPhVv?xo{!{l+}aL|Q^xx39rVg8O2JZ+ zUL#oa0ey^nfbLm~l}%~VI-W>9hN-dCCNeCSc8`kR-WuN`w%9kJ=lC9UD-8&8_8M%c zT<_NRB7lNX(CSG)&8Dsp-XTxsj8WI~zkQ6ey{y#k2636sJoWqWvuby=vI_f;A?dcq zy}If??I))$uREe;BH5{yEvvGWY%sj*?6>GiYTKB0&p$IG5wWrFLaBv~bAwC|y+^SR zOwe=qJp}=370I`1n8YWByd$t2p33JY+wP4{4RQUdp z1>@qFAcRf!+haggBgrC=-M+{00A<$_+D4>5tn~*KZ+@ipTG~%+&!#|op{2nEzy)q) z?QZ3a`N0&0H*A=C40n~z>Sv_RL0YX3-UM!vnVA`^CR2+(Hxl5hQWg3Nm&y(I9l(Nh z&=30K8?hjs0mx}%8igf3eS7EymiiQmnD@@>lPDaK%HExvB0Q;Wmd^_+o-Iva^AbgFS4>E|{&gP+do-U?m*h(y(PsGO#aC;QLGc zNDkIH?6+HDy}5G2mkU|6!=mwR^P7sLr><9?d~Put^L_B9dnVgvWfx>TkbD4X=O2pZpx7vQ64EEj(Kk>z#ht)Lc_Z=NOecqwgBHj13 z+Iyw01V!FKZ;w;1pTo6v0;jy09LrapeW@udV!c{0^HDt<$Vara%QsS61>}{4C%}t5 z_k9q)D`SwP0KkBR-SrQLM$!i;XS@IwBYgtglU^(eAw|FO+U~{H(*47IiL_nNkq;* zNTxBU-+-2QMGek(WPV09glJt!`wu+09mv2mj(xd`e}c|{O^EF#qt*moQ9xG7b&Pl* z=@^CJB|H!KoseGbg`S0g+I)vfdP<#}wrI3TD{%J_ zC!h6)fAGKWU^OOKzP+hTJI&p*u-R#eLG8=QovjV2haFo)pGUK2e|Ay(CBRuY|Ds65 zcUk!71;wvDy$8~xvaMNAK2{t_`-q_=_Qzo)rD*eBde*F#al$l;)vWUJXYmOpcJ|A- zw$!D+0F@v*4fRmL`CicKAvC4mA=?X7sefCp^fjZG>S&eiCtK;I0j z?T_*%s(>IxnmSxWU#{k)AImWU6|d#uq~^@^uycVmc#-GY%x9~sKzk0 z!_Xn~uDiQm`g(*;j&@|l4QAF^=cey7DZu>WcpCeR2Z6|q*R{27%b#(3L64K>YGN4D$tylXk$s z6i*WnEI58}cx=-jllZ3kw76SGg!7c~99CL9=upEeVr4)C%x_R9ufP5VT@5K<*J?RtS_3dDL@gQ$)US<&m1u8KV9oMd21u@)Z z%oihs5(R#z-swhY7xtXDyG?&*t&F~5nhyS<-PabfX6KOYl8d(gOc+J;MuXAJ+Z6uB z6tC92zB*f!PxNUsP0M~6``Ukw!4Ek9tH-qBPr$lzDXl+_Nt=n^^S}JQzFI3{k7*3KJdMkq zCX6b4WcFV{G&qd#lo-s&kOeur#LRUgNX;WXpo+mf9Rc}6L|FJUwjVSHy1MTmqJ(BA zeO@caSPw!cIDid$ZWXwJegeZrOfzOdDR6V^kJ^D4IXKQK9LsAt9casc?tx|!E*o5v zFvNs~Ctj1&(^@(@;92eD9o(1srN*GW=+`gbP)9Y-I|c;9Xbs!A(l1ddf~fxT$L-+e znson58Y2Qceml9QnIecPN`@-en+~4awtt~zez8HF82<70fV|OnZZ3+x6y-y=l*P=I zXw?Jss`y2JAGdgUo3gx#`Y6@24DToHo*CQji_=x-3KhLA12MWss(}FA^KI@A#g)lT zAu6PEY6B-dffR3yZ1-25)&K@;AN^fwmwg{VWgtDx^7B0?A&EY$n;^L5#r7en1e+?? zT?VSjC*C-Gl3AK=^s;}lSn?L=nHc+)V67+bN(ghW1_y&1?uhlj=i`N8fuI8_`RD$o zsY|k4J^c3V(&jt7QM>&)*Jqn;$o*M(SxYbV4i$w)dTEkIh7?6rm(Wi``6ST-raM%n z%kRqfb~EmrUf${JV^QnCJ*FK|dSfP~K9ra+F7z)=iq+>xBh>RJ)kI+7$*zS3Ca6BI6l~Yr85IXx6LW$SzzFosc?OL z@fur z5Td(`Gi_&Yx%=JLzy8*>-1yS!sPV4D#UE6XuGs5~B-6;~+#6x(UuL??LlLXYXvF_9 z@B2D!1Ct2-8a>|~3U%$fBexS(7TPO}B5Xb{Uc7k=p}{0T@AJ;bA7HyR62j2b$(drm zMmVT9b$WHEVZC1;TodOzho!z&NKsY-D-hOgQeP!yx>9R;M_q!o2^Cq!n0+HSzdRaa zV`X67oav-Gd<5KXP{wn=yk(WA%rQDU??}O4=Cm_jN{OGj(0ad`?(OJ{pAFwP2m9r> z(GY7{ZCv;^(>iB-H}A3*WT` zJfeD{AuaP(prn4G>6|<*!+7H#u4BJ1-j*^xLrDOmN25;Nx&aVv-N0$%IVFy}FW;N} zYJdHD_pV)6Xft5zL&`G&?_7G;aId7JATve7B%@F%3WRLf4dw$9#DEwq;K`|}E)W&9 zqzsjs`lc5>INraB1twj6XjZ6&yB{$p$V}ky2zj4qk0J`-DBKbu8vt+vs`J_Ml1<(c z87+A=B$``={{)+G3%N)N{SQ&~bAhv}$u#lnc4_2Jit=~Io0N83XK`*^X+)cqycV=E7`aZ2Q%VAI>Qar$W^Ub92ok9N1h|&$uL4kV&9E z|A6kJy#kvZ7^}tLTziEo0mza)gx;wern+rPMRM_ zxvZJ0#WMD$t`-jo0iuGQj(z&36dYoaNrKccJ(2rs4#Hmz^Dgwc5l)DIjZe7_c_NC@ zm9N)0FxkR5sqk#)hxkM5GM6F^%@+Y|QIJtd5VxBN$qS)Vf-dmQAlKbt%=$M3Qxac% zrkhBTA=U=W3o%+Eb6L@#N2ikgHluTKncKf1Fppuz_ZbmLil{dz3{AYBrjm)cknMo^g;vyr+@wtGw%U+{a$ zu@llVGQedV@h^{tx3@RECS5=TL>D3oZnBvbPz&H_|3K@)!FYrRpHq4^r@Wk zfz6mS%zjF-)i~0ILJKqqP~*M8z`@D~PhtG5Q#iWzYoOC-(!QOXn~RkNXL)4vXFep(Q=;>$iH7NbjL+%qs9gjeDZ|F%-!Lyw&yBir<0FDlC*bXH4 z`S_IW77#A4LnVR}1p1ZQ7zK9_!|$;iJtJ&8Au0)Rmw(s2aE5ROY~_3rm=Azf_05Sy z$mP7mFxQ5749GdR>aD(d$fD+uFaw*)w%%Sp;7vIGbyzeEQQhJvLEFi7q=BsvC=4)- zib?TrVA!EdGYZc|?*^lPxTOw|>CAYUB(TO8zExB4aDOV~St@N%aq9WQe&I(W?Ol^q zcl9QsGY%Y7cE7jM@>ZX({^<3a3@t}rDy%Yq7y+JDlTDtx75aU&Z4tFcnG3LLU}OR> z5KF|~;&%9hJ4#^m%l!c~MI_)3NrB?;;Y47^L=_}nU@-vdTg1%>uENvWGdYDee|m-4;ZoU2c1#A%YE~{0Y#RF zZTAv%^H2PC{urq7yH_@|^={L;pPQOx-u?PiQ#WoW>V491JwYX-Z|beNnpEcLaiAvh z3&%=r>A~Ukx!q!C1D~EX2eBMN^@d!WBD{DsWMyRFfZ`Sgkm+tIKGU-FBu$5|I$KC9 zoW3_1qp6@wGm$vZmoWB8-vn}*G~LavOqO8Ixnvv1irCUWxkY^+wcJw#Z*7wOaz#yg zdOab1(&~|SNoLnug;zI4e)6#Y?ChC6_ba8tZ~0P0y2izzG=D1p>fKk34afMrX^W@y zatka5M-sX_SEFTu*rR-PI{`w0G_yXyvQx3*w1f^)jCnwa*c~2n0pEv&4 zYOQ3n{3EaOM_%r{bAG$8nzZ_s@FyJH#r1Xmu-Aso+ehB)&vVZ0@iMF>{P*e5Ie+Dg zWV4ugx|Zh=|NgCZ+X=6ifxWsabN8m{g_e#zIWKoOw z#FSIj^lVIcK_;zh*N25@T$!T+T zp-i!!qE6+&yJkI-?DF)0sZcY@)t8&nHNc{3^G`ay{cs35FO{-R$`KQV8Q9h z@L@ggqnU*+yO}9+PV!9elhimvO{nwt*LrN`ySJUag{#C%o6_K+3GphS&2}{d9 z=Q<8XEgYKP_cD-Z2G=S6&`&YRxcv6JoW7>!4Kop# z%H6B8hP5OpygjZx*yT_OjGgmka5$tn+gQ&QeR_?x(#E!r4z2j-6`lLHgSCs>2_o3U z?ffFgO|3IN%Ib{mj($Qn^650H9_9c3GsLv3Cg<=rN2y<#x9RUq5##RsYtl0_E(|a& zpIrFNbi8M5?#_`x@9&AGI-Y);z0byu+zka{0y+T2LD)Otlt7D4VTo#?eWy-PSAsW_ zmT~V&`Lt(#Tc2n=uNQJ~>$xj7MBX-(@U>FC-32tIj9_m3Tjex-QDv;oY$>r2!9lstz4=XgsS! zE5&hVdOgMAdm|6GW~#aOZ9aLX?EI^z?ZI2TlUGxtsnu@qzk0}f!+rkajzk9S$@tSE zZ7x5T^lUXULX3Txu35DlVz~J_YHiG1fK`Zo_k_Mx>OK9mLp6s@zJGRfAg;Uii_$Rq zUQ%22rOg~$nC7SCnLkh2kgeYvutheHGKgD#WXt~iy5p+E!ubdH^ca7oq?I(NGdS!5 zk0kcwrY%u4@(t)Q;zrggfWo7%Wog6(_JGvC_eYzQ#Nxj1H1X8x;b*_!Ph~IvSF>@Y z_ELLMkMdhy_OK4t%6qrSHw*uGnt&(vtbgv)NQUreL?^Egct65k9MaES&2&7d>lXZs zQDrjF(0u#qx0N=&Qa0)gJ@p|+p56HMZH1`nPy9CZXKz<0wU_R+7>iL9^iCdGWV=#$CD|V7QBO^;yl;JHE#4w=ZrQ(okV(;t;_CKLf;Enu+)Y)uV|4(>B`YZELF==1&+wA|&cJwoTxu9E-yFD$t_t zTk{RXeE=Mg$YYrSJra^ld;sVN_2yB*$c!#Aoc@d&Co6KI2M`$v;Z`67XO+*HAY>Mt z1E?`5s{Wg11G>^#npw0VPMD&HHfV$|fpCJ^C-!Yn?J6;D2aE#mrscY#)>{}J%JI+r zv)n>(+W{3iiff22@d85?9aD5P$rNqW3Sw}$`AltWNHRS*0XRhtbcpylh*yDZnvaL) z0;c~+EeD}*Am8&LdXlb>M%{mmkc=CiGpcsdm8E13* zRRLk)0=b)eI3(;CG{O%bK1}re_#uZ7Dj>KR!O>C$fDL&g0eKIykX}Ld05>B73LbKr z2_E^ma~a13p<+BYA)_6qung!eYI6r*6`12eBncEB24L_=K#3m

?xg-|%)g1c$2j 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 a8r`xrSs(7KJlrsg=jd^~d2Bf=EcG9>g;EUw literal 0 HcmV?d00001 diff --git a/api-docs/development/Libraries/index.html b/api-docs/development/Libraries/index.html new file mode 100644 index 0000000..ba18da3 --- /dev/null +++ b/api-docs/development/Libraries/index.html @@ -0,0 +1,1708 @@ + + + + + + + + + + + + + + + + + + + + + + + Libraries - University Polling + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

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

Libraries

+

This file lists the libraries used in this project with a link for the documentation, a short description, an explanation of use, and optional examples.

+

Back-end developments Libraries

+

FastAPI

+

FastAPI is a framework to create back-end server APIs, an alternative to Flask or Django. Compared to other frameworks, it's minimal, yet provides most common functionalities for creating web API. FastAPI supports HTTP requests as well as web-sockets protocols, both of which are used in PollingApp project.
+Important aspect of FastAPI is multi threading support of asynchronous tasks, which allows handling many requests simultaneously as well as scheduling heavy tasks to not conjugate the app flow. For those reason, this framework is a popular choice due to great performance(on part due to uvicorn event loop) as well as extensive documentation

+

Pydantic

+

FastAPI is built on top of Pydantic library, which provides data validation and settings management using Python type annotations. Pydantic also enforces type hints at runtime, and provides user friendly errors when data is invalid. The pydantic models are much improved Data classes in python. The improved functionality allows seamless use in all parts of web application. The schemas that define request and response formats are based on Pydantic model, as well as database schemas for storing data and much more. Lastly, Pydantic provides a mypy plugin to further assist validation of types.

+

Beanie

+

Beanie - is an asynchronous Python object-document mapper (ODM) for MongoDB. It is based on async. version of Motor library. Data models are based on Pydantic models. When using Beanie each database collection has a corresponding Document that is used to interact with that collection. In addition to retrieving data, Beanie allows us to add, update, or delete documents from the collection as well.

+

FastApi Users

+

Framework that is build on top of FastAPI to provide User functionality. We use beanie version, to store user data in mongo database. +The library provides class that manages various events like authentication, some predefined routes. It automatically stores and updates information in the database. The library also provides a basic User model(email, password), which is further expanded in /models directory(added first and last names, group lists, etc). Some users can take on a role of a superuser, that grants them right to change information of other users or delete accounts. Super users can be considered the managers of the server, for instance technical support.

+

Predefined routing:

+
    +
  • To Register
  • +
  • To Login
  • +
  • To Request a token and reset password
  • +
  • Basic CRUD routes to read, update, delete users, etc
  • +
+

The routes will use schemas for requests and responses, which can be found in app/schemas/user.py

+

Testing Libraries

+

This libraries are used for testing. Please check out the Testing Wiki to learn more about the actual tests.

+

Pytest

+

Pytest is a software testing framework based on the Python programming language. It can be used to write various types of software tests, including unit tests, integration tests, end-to-end tests, and functional tests. Pytest has been described as a scalable framework with less boilerplate code. Its features include parametrized testing, fixtures, assert re-writing, and test filtering

+

FastAPI provides built-in functionality for testing API end point using pytest and httpx library to create a test client.

+

Pytest coverage

+

This plugin produces coverage reports. Compared to just using coverage run this plugin has extras features, and works well out of the box with tox and other tools.

+

Flake8

+

Flake8 is a Python linter, which ensures that the code follows pep8 styling guide, such as spaces, indentation, etc.

+

Mypy

+

Mypy is an optional static type checker for Python that aims to combine the benefits of dynamic (or "duck") typing and static typing. Mypy combines the expressive power and convenience of Python with a powerful type system and compile-time type checking. Mypy type checks standard Python programs; run them using any Python VM with basically no runtime overhead. It works very well with Pydantic plugin to make sure all the right types are used for functions and models.

+

Tox

+

tox aims to automate and standardize testing in Python. It is a generic virtual environment management and test command line tool. tox allows us to create multiple virtual environments with different python versions and run multiple test, such as flake8, mypy, etc. Coupled with tox-gh-actions. It becomes a powerful tool that can help testing project on various systems automatically using GitHub Actions.

+

Faker

+

This Library is used for generating random data such as names, email, address, etc. It's useful for testing.

+

Distribution and packaging

+

This libraries are used for building and deploying the package

+

Setuptools

+

Setuptools provides powerful tools to handle package discovery, including support for namespace packages. It is built on top of Distutils. +GitHub action will use setuptools to install all dependencies required for testing. +With an addition of build the application can be easily deployed to various systems as a package, which simplifies the installation.

+

Build

+

A simple, correct PEP 517 build frontend. By default, a source distribution is built from source and a binary distribution (wheel) is built from the distribution. This is recommended as it will ensure the distribution can be used to build wheels.

+
$ python -m build .
+
+

The result of this command will be a tar ball with all the code required to install and run the application.

+

Gunicorn

+

Gunicorn 'Green Unicorn' is a Python WSGI HTTP Server for UNIX. It's a pre-fork worker model. The Gunicorn server is broadly compatible with various web frameworks, simply implemented, light on server resources, and fairly speedy.

+

WSGI applications are a single, synchronous callable that takes a request and returns a response. This doesn’t allow for long-lived connections, like you get with long-poll HTTP or WebSocket connections, which WSGI doesn't support well. So we use uvicorn workers controlled by gunicorn process. Combination with NGINX as a reverse-proxy, it handles all of the connection and communication between client and the API application.

+

Uvicorn

+

Uvicorn is an ASGI web server implementation for Python. It supports HTTP/1.1 and WebSockets. However it has some limitations in terms of compatibility(The uvloop implementation provides greater performance, but is not compatible with Windows or PyPy) and for production deployment purposes. Although, the uvicorn can be used for development, it is recommended to use Gunicorn for deployment,

+

console x +Run uvicorn --reload from the command line for local development. +Run gunicorn -k uvicorn.workers.UvicornWorker for production.

+ + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/api-docs/development/Release/index.html b/api-docs/development/Release/index.html new file mode 100644 index 0000000..79b97ea --- /dev/null +++ b/api-docs/development/Release/index.html @@ -0,0 +1,1462 @@ + + + + + + + + + + + + + + + + + + + + + + + Project Build and Release - University Polling + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

Project Build and Release

+

Semantic Versioning

+

Semantic versioning is a way to version software in a way that is easy to understand and use. +It is a set of rules that dictate how to increment the version number of a software package. +Semantic versioning is a way to communicate changes in a software package to users and developers. +Example:

+

Learn more about semantic versioning at semver.org

+

Docker

+

Running the API in a docker container is the easiest way to get started. To build the docker image, run the following command:

+

Building the image

+
FROM python:3.11
+
+WORKDIR /unipoll-api
+
+COPY ./requirements.txt /unipoll-api/requirements.txt
+
+RUN pip install --no-cache-dir --upgrade -r /unipoll-api/requirements.txt
+
+COPY ./src /unipoll-api/src
+
+CMD ["uvicorn", "src.app:app", "--host", "0.0.0.0", "--port", "80"]
+
+

Running the image

+
docker run unipoll/api -e MONGODB_URI=<your connection string>
+
+

Docker Compose

+

...

+

Building the Distribution

+

To build the python package, run the following command:

+
python build .
+
+ + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/api-docs/development/Structure/index.html b/api-docs/development/Structure/index.html new file mode 100644 index 0000000..8d0b4e8 --- /dev/null +++ b/api-docs/development/Structure/index.html @@ -0,0 +1,1494 @@ + + + + + + + + + + + + + + + + + + + + + + + Project Structure - University Polling + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

Project Structure

+
├── actions
+│   ├── account.py
+│   ├── authentication.py
+│   ├── group.py
+│   ├── members.py
+│   ├── permissions.py
+│   ├── policy.py
+│   ├── poll.py
+│   ├── superuser.py
+│   └── workspace.py
+├── exceptions
+│   ├── account.py
+│   ├── authentication.py
+│   ├── group.py
+│   ├── policy.py
+│   ├── poll.py
+│   ├── resource.py
+│   └── workspace.py
+├── routes
+│   ├── account.py
+│   ├── authentication.py
+│   ├── group.py
+│   ├── poll.py
+│   ├── websocket.py
+│   └── workspace.py
+├── schemas
+│   ├── account.py
+│   ├── authentication.py
+│   ├── group.py
+│   ├── member.py
+│   ├── policy.py
+│   ├── poll.py
+│   ├── question.py
+│   └── workspace.py
+├── utils
+│   ├── auth_strategy.py
+│   ├── auth_transport.py
+│   ├── cli_args.py
+│   ├── colored_dbg.py
+│   ├── permissions.py
+│   └── token_db.py
+├── account_manager.py
+├── app.py
+├── config.py
+├── dependencies.py
+├── documents.py
+├── mongo_db.py
+├── __version__.py
+└── websocket_manager.py
+
+

Main files

+

app.py - Contains the main app. The app is responsible for starting the server and loading the configuration.

+

config.py - Contains the configuration class. The configuration class is used to load the configuration from the environment variables.

+

dependencies.py - Contains the dependencies class. The dependencies class is used to load the dependencies.

+

documents.py - Contains the document classes. The document classes are used to define the structure of the documents in the database.

+

mongo_db.py - Contains the database class. The database class is used to connect to the database and perform operations on the database.

+

__version__.py - Contains the version of the API. The version is used to identify the API, in case the project metadata is not available.

+

websocket_manager.py - Contains the websocket manager class. The websocket manager class is used to manage the websocket connections.

+

Actions

+

This directory contains all the actions that can be performed on the resources. Each action is a function that takes a request and returns a response. The actions are called from the routes.

+

Exceptions

+

This directory contains all the exceptions that can be raised by the actions. Each exception is a class that inherits from the base exception class. The exceptions are raised by the actions and handled by the routes.

+

Routes

+

This directory contains all the HTTP routes. Each route is a function that takes a HTTP request and returns a response. The routes are called from the main app.

+

Schemas

+

This directory contains all the schemas that are used to validate the request body and response body. Each schema is a class that inherits from the base schema class. The schemas are used by the actions.

+

Utils

+

This directory contains all the utility functions and classes. The functions and classes are used by the actions and routes.

+

auth_strategy.py - Contains the authentication strategy class. The strategy class is used by the authentication action to authenticate the user.

+

auth_transport.py - Contains the authentication transport class. The transport class is used by the authentication action to send the authentication request to the authentication server.

+

cli_args.py - Contains the command line arguments parser class. The parser class is used by the main app to parse the command line arguments.

+

colored_dbg.py - Contains the colored debug class. The debug class is used by the main app to print colored debug messages.

+

permissions.py - Contains the permissions class. The permissions class is used by the actions to check if the user has the required permissions. It contains definitions of all the permissions as well as functionality to check if the user has the required permissions.

+

token_db.py - Contains the token database class. The token database class is used by the authentication action to store the access tokens and refresh tokens.

+ + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/api-docs/development/Testing/index.html b/api-docs/development/Testing/index.html new file mode 100644 index 0000000..c4ed72d --- /dev/null +++ b/api-docs/development/Testing/index.html @@ -0,0 +1,2018 @@ + + + + + + + + + + + + + + + + + + + + + + + Local Testing - University Polling + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + +

Local Testing

+

Back-End Testing

+

Pytest

+

This library is used for unit testing. An alternative to default unit-testing package. The biggest difference between two libraries is that Pytest can run tests simultaneously for saving time. It supports Fixtures and use testing asynchronous functions. Most importantly it comes almost ready out of the box with FastAPI.

+

Pytest can be run on specific files or the whole directory by passing arguments:

+
$ pytest
+...
+$ pytest tests
+...
+$ pytest tests/test_1_users.py
+...
+
+

In addition, test occasionally print out the information(custom messages) about the current test. By default pytest hides user output, this can be fixed with -s argument. +For example:

+
$ pytest -s
+=============================== test session starts ================================
+platform linux -- Python 3.11.0, pytest-7.2.0, pluggy-1.0.0
+rootdir: /home/mpisman/Documents/PollingApp, configfile: pytest.ini, testpaths: tests
+plugins: trio-0.8.0, anyio-3.6.2, cov-4.0.0, Faker-15.3.2, asyncio-0.20.2
+asyncio: mode=Mode.AUTO
+collected 10 items
+
+tests/test_1_users.py
+
+TESTING:  Registering new user:  agilbert@ucmerced.edu
+INFO:     User 639e94f54c8775804e127b92 has registered.
+SUCCESS:  New user ha been registered:  agilbert@ucmerced.edu with id:  639e94f54c8775804e127b92
+.
+
+TESTING:  Attempting to register a new user with an existing email:  agilbert@ucmerced.edu
+SUCCESS:  The new user failed to register because email already exists:  agilbert@ucmerced.edu
+.
+
+TESTING:  Attempting to login with incorrect email
+SUCCESS:  The new user received a 404 "LOGIN_BAD_CREDENTIALS" error
+.
+
+TESTING:  Attempting to login with incorrect password
+SUCCESS:  The new user received a 404 "LOGIN_BAD_CREDENTIALS" error
+.
+
+

Tests User functionality

+

Test to see if the user can create an account

+

1) Try to Register a new user (Success) +2) Validate: status is 201 +3) Validate: id, email, first name, last name

+

Test to see if the user can register with an existing email

+

1) Try to register a new user with the same email (Fail) +2) Validate: status is 400 +3) Validate: details = "REGISTER_USER_ALREADY_EXISTS"

+

Test to see if the new user can login with the incorrect email

+

1) Try to login with the incorrect email (Fail) +2) Validate: status is 400 +3) Validate: details = "LOGIN_BAD_CREDENTIALS"

+

Test to see if the new user can login with the incorrect password

+

1) Try to login with the incorrect email (Fail) +2) Validate: status is 400 +3) Validate: details = "LOGIN_BAD_CREDENTIALS"

+

Test to see if the new user can login with the correct credentials

+

1) Try to login with the correct credentials (Success) +2) Validate: status is 200 +3) Validate: token_type = "bearer" +4) Validate: access_token field exists in the response and it is not empty +5) Set temp user token to the access_token to be used in the next tests

+

Test to see if the user can get their own information

+

1) Try to get the user information with the token passed in the header (Success) +2) Validate: status is 200 +3) Validate: id, email, first name, last name, is_active, is_superuser, is_verified

+

Test to see if User can delete their own account

+

1) Find user by id to make sure it exists (Success) +2) Try to delete the user +3) Validate: status is 204 (Success)

+

Test Group functionality

+

This test relies on the user functionality to be working correctly, and uses the functions from the previous test.

+

Test to see if the user can create a group

+

1) Create a temporary user(group owner) for test and login (Success) +2) The new user requests list of groups(should be empty) (Success) +3) Validate: status is 200 +4) Validate: the list of groups is empty +5) The user creates a group (Success) +6) Validate: status is 201 +7) Validate: id, name +8) The user gets list of groups. (Success) +9) Validate: status is 200 +10) Validate: the length of the list of groups is 1 +11) Validate: the only group has the name of the group created in step 5 and the role listed as owner +12) User gets the group information by id. (Success) +13) Validate: name, description, owner name and email +14) The user gets list of admins. (Success) +15) Validate: status is 200 +16) Validate: the length of the list of admins is 0 (the owner is not counted) +17) The user gets list of user (a member of user role) (Success) +18) Validate: status is 200 +19) Validate: the length of the list of members is 0 (the owner is not counted) +20) The user gets list of members (any member) (Success) +21) Validate: status is 200 +22) Validate: the length of the list of members is 1 +23) Validate: email and role of the member is the owner +24) The user get the owner information (Success) +25) Validate: status is 200 +26) Validate: email and name of the owner

+

Test to see if the user can add other users to the group

+

1) Register 13 new users, storing 3 in one list(admins) and the rest in a separate list (regular users) (Success) +2) The owner sends a request to add members from the payload. which is a dictionary of user emails and their roles (Success) +3) Validate: status is 201 +4) The owner gets list of members (Success) +5) Validate: status is 200 +6) Traverse the list of members and validate that all users have been added (Success) +7) The owner gets list of users (Success) +8) Validate: status is 200 +9) Validate: the length of the list of users is 10 +10) Validate: the list of users contains all the correct email addresses +11) The owner gets list of admins (Success) +12) Validate: status is 200 +13) Validate: the length of the list of admins is 3 +14) Validate: the list of admins contains all the correct email addresses

+

Test to see if the user can delete a non-existing group

+

1) The owner sends a request to delete a group that does not exist (Fail) +2) Validate: status is 404 +3) Validate: details = "Group with id {id} not found"

+

Test to see if the user can delete a group they own

+

1) The owner sends a request to get the group information (Success) +2) Validate: status is 200 +3) Validate: name +4) The owner sends a request to delete the group (Success) +5) Validate: status is 204 +6) The owner sends a request to get the group information (Fail) +7) Validate: status is 404

+

Naming convention

+

For pytest to recognize test files, the file name should have a prefix test_. By default, pytest runs test files in the alphabetical order, so to make test run in a specific order, the easiest solution is to name them as test_ORDER_NAME, where order is an integer, and name is a short description of the test. +For instance: +./tests/test_1_users.py +./tests/test_2_groups.py

+

Pytest configuration

+

The small configuration can found in ./pytest.ini: + - Sets pytest to use asyncio + - Adds all files inside ./tests/ for testing + - Specifies some common warning which should not be displayed

+

Fixtures

+

Another file, ./tests/conftest.py, provides fixtures for database use and asynhronous client to make requests in the same session.

+

Pytest Coverage

+

We use pytest-cov to provide additional information of testing coverage in terms of code lines. Basically, the pytest keeps track of which lines of source code have been executed during tests. Ideally, the coverage should be near 100% on all files, which would indicate that all code has been tested in some way.

+

Here is example of coverage report that will be provided at the end of each test: +

---------- coverage: platform linux, python 3.11.0-final-0 -----------
+Name                         Stmts   Miss  Cover
+------------------------------------------------
+app/__init__.py                  0      0   100%
+app/app.py                      24      0   100%
+app/config.py                   12      0   100%
+app/exceptions/__init__.py       1      0   100%
+app/exceptions/group.py         30     11    63%
+app/exceptions/user.py          19      9    53%
+------------------------------------------------
+TOTAL                          474    105    78%
+
+In the example above, since some of the exceptions were not tested, we only got partial coverage.

+

Faker

+

This Library is used for generating random data such as names, email, address, etc. It's useful for testing.

+
fake = faker.Fake()
+print(fake.email)
+
+

Flake8

+

Flake8 is a combination of tools that checks that files follow pep8 styling format. The configuration can be specified inside pyproject.toml. The only difference I made from default configuration is maximum length of the line, the default value of 80 is too small for modern widescreens, so we use 120 instead. Otherwise the formatting becomes to tedious.

+

After running, the tool will output a line number that needs to be fixed as well as short description of the error. Therefore, a successful run will have no output.

+

Examples of erroneous run:

+
$ flake8 app --max-line-length=120
+app/app.py:13:1: W293 blank line contains whitespace
+app/app.py:54:1: E302 expected 2 blank lines, found 0
+app/app.py:67:6: W292 no newline at end of file
+app/config.py:9:51: W291 trailing whitespace
+app/config.py:10:1: W293 blank line contains whitespace
+app/config.py:13:1: W293 blank line contains whitespace
+app/config.py:14:1: E302 expected 2 blank lines, found 1
+app/config.py:16:22: W292 no newline at end of file
+app/exceptions/__init__.py:1:1: F401 'app.exceptions.group' imported but unused
+app/exceptions/__init__.py:1:1: F401 'app.exceptions.user' imported but unused
+app/exceptions/__init__.py:1:39: W292 no newline at end of file
+app/models/user_manager.py:22:1: W293 blank line contains whitespace
+
+

Mypy

+

There are many good reasons to use typing in Python application. However, one of the bigger benefits comes from using Pydantic models. By defining types, Pydantic will automatically implement validation check, when you will try to set/update the value. If the type of value differs from the one you have defined before, Pydantic will raise an error. FastAPI further extends this functionality by using Pydantic models for schemas of HTTP requests and responses. Meaning, if a user will try to send data that does not follow the schema, they will get a "422 Unprocessed entity" error. Vise versa, if server will try to send a response that does not follow the schema, it will most likely fail due to exception. For this reason, typing is crucial in the fastAPI application.

+

Mypy is a static type checker library for Python, which helps solve the issues described above. Coupled with Pydantic plugin it check all of the modes and function, and it manages nested types very well.

+

On successful run you should get the following message.

+
$ mypy app
+Success: no issues found in 20 source files
+
+

In case of any errors, the mypy will provide a detailed output.

+
$ mypy app
+app/utils/colored_dbg.py:1: error: Library stubs not installed for "colorama"  [import]
+app/utils/colored_dbg.py:1: note: Hint: "python3 -m pip install types-colorama"
+app/utils/colored_dbg.py:1: note: (or run "mypy --install-types" to install all missing stub packages)
+app/utils/colored_dbg.py:1: note: See https://mypy.readthedocs.io/en/stable/running_mypy.html#missing-imports
+app/mongo_db.py:2: error: Skipping analyzing "motor.motor_asyncio": module is installed, but missing library stubs or py.typed marker  [import]
+app/mongo_db.py:2: error: Skipping analyzing "motor": module is installed, but missing library stubs or py.typed marker  [import]
+app/routes/group.py:19: error: Module "app.schemas.user" has no attribute "UserID"  [attr-defined]
+app/tests/test_users.py:51: error: "Response" has no attribute "get"  [attr-defined]
+app/tests/test_groups.py:123: error: Value of type "Response" is not indexable  [index]
+
+

At times, third parties do a poor job of specifying types for parameters of functions and their return objects. In case of error/warning that is not fixable, you can place a comment on the same line causing error to ignore type check.

+
some_function()  # type: ignore
+
+

Tox

+

tox aims to automate and standardize testing in Python. It is a generic virtual environment management and test command line tool. tox allows us to create multiple virtual environments with different python versions and run multiple test, such as flake8, mypy, etc. Coupled with tox-gh-actions, it becomes a powerful tool that can help testing project on various systems automatically using GitHub Actions.

+

The configuration can be found in tox.ini

+

We use 2 Python versions(3.10 and 3.11) with the latest ubuntu image(this also has to be specified in workflows). However, other versions of python can be easily added, as well as, other operating systems. Tox creates a virtual environment for each python version and runs all tests inside of it. First it runs pytest, then flake8 and mypy.

+

At the end of all tests, you should see a message indicating that tox has successfully ran all tests using 2 virtual environments(python +3.10 and 3.11), and it also ran mypy and flake8. In case of any errors tox will let us know.

+
  py310: OK (18.02=setup[5.09]+cmd[12.93] seconds)
+  py311: OK (17.10=setup[4.27]+cmd[12.83] seconds)
+  flake8: OK (3.95=setup[3.77]+cmd[0.18] seconds)
+  mypy: OK (4.19=setup[3.78]+cmd[0.41] seconds)
+  congratulations :) (43.31 seconds)
+
+

Automated testing with GitHub Actions

+

Github actions allow us to automatically run tests, update documentation, release new version of builds, and other.

+

In our case, we use GitHub actions to run tox tests on every on pull request to the Development branch. This is a great way to ensure that the code is always in a working state before releasing a new version.

+

The configuration can be found in .github/workflows/python-app.yml. The workflow will fail if any of the tests fail. As an indication of success or failure, you should see a green checkmark or a red cross next to the commit and a badge on the top of the README file in the Development branch.

+

Like this: Tests

+

Postman Testing

+

Postman is a great tool for front-end developers. It can help with testing the API without having to learn the back-end. It provides a GUI for testing APIs called flows.

+

More testing with postman coming soon...

+ + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/api-docs/development/index.html b/api-docs/development/index.html new file mode 100644 index 0000000..d0ad941 --- /dev/null +++ b/api-docs/development/index.html @@ -0,0 +1,1360 @@ + + + + + + + + + + + + + + + + + + + + + + + Development - University Polling + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

Development

+

Quick Start

+

Clone the repository:

+
git clone https://github.com/unipoll/api.git
+
+

Or using GitHub CLI:

+
gh repo clone unipoll/api
+
+

Create a virtual environment:

+
$ pip install virtualenv
+
+
$ python -m venv venv
+
+

Activate the virtual environment with

+
$ source venv/bin/activate
+
+

Install dependencies:

+
$ pip install -r test-requirements.txt
+
+

Run the app:

+

You can use the main.py script to run the app.

+
$ python -b main.py run --reload --port 8000
+
+

Install editable package:

+

Alternatively, you can install the package in editable mode. Editable mode allows you to make changes to the source code and see the changes reflected immediately.

+
$ pip install -e .
+
+
$ unipoll-api run --reload --port 8000
+
+ + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/api-docs/index.html b/api-docs/index.html new file mode 100644 index 0000000..0efe794 --- /dev/null +++ b/api-docs/index.html @@ -0,0 +1,1319 @@ + + + + + + + + + + + + + + + + + + + + + + + University Polling API Documentation - University Polling + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

University Polling API Documentation

+

Here you can find the API documentation for the various components of the University Polling API project.

+

Project Goal

+

The main goal of the project is to provide a simple and easy to use API for developing client applications. The API should be easy to extend and maintain. The project follows RESTful API design principles. You can connect using HTTP or WebSockets.

+

Features

+
    +
  • RESTful API
  • +
  • WebSockets API
  • +
  • Registration and Authentication
  • +
  • Attribute Based Access Control
  • +
  • User Management
  • +
  • Support for Groups and Organizations
  • +
  • Creation and Management of Polls
  • +
  • ...
  • +
+

Contents

+
    +
  • Learn how to configure the API in the Configuration section.
  • +
  • Learn how to extend the API in the Extending section.
  • +
  • Learn how to contribute to the API in the Contributing section.
  • +
+ + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/api-docs/usage/API Reference/index.html b/api-docs/usage/API Reference/index.html new file mode 100644 index 0000000..b339078 --- /dev/null +++ b/api-docs/usage/API Reference/index.html @@ -0,0 +1,11302 @@ + + + + + + + + + + + + + + + + + + + + + + + API Reference - University Polling + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

API Reference

+

Authentication

+
    +
  • +

    oAuth2 authentication.

    +
      +
    • +

      Flow: password

      +
    • +
    • +

      Token URL = auth/jwt/login

      +
    • +
    +
  • +
  • +

    API Key (APIKeyCookie)

    +
      +
    • Parameter Name: fastapiusersauth, in: cookie.
    • +
    +
  • +
+

Workspaces

+ +

get_workspaces_workspaces_get

+

+
+

Code samples

+
+

GET /workspaces

+

Get Workspaces

+

Returns all workspaces where the current user is a member. +The request does not accept any query parameters.

+
+

Example responses

+

200 Response

+
+
{
+  "workspaces": [
+    {
+      "description": "This is an example workspace",
+      "name": "Workspace 01",
+      "owner": "true"
+    },
+    {
+      "description": "This is another example workspace",
+      "name": "Workspace 02",
+      "owner": "false"
+    }
+  ]
+}
+
+

Responses

+ + + + + + + + + + + + + + + + + + +
StatusMeaningDescriptionSchema
200OKList of all workspacesWorkspaceList
+ + +

create_workspace_workspaces_post

+

+
+

Code samples

+
+

POST /workspaces

+

Create Workspace

+

Creates a new workspace for the current user. +Body parameters: +- name (str): name of the workspace, must be unique +- description (str): description of the workspace

+

Returns the created workspace information.

+
+

Body parameter

+
+
{
+  "description": "This is an example workspace",
+  "name": "Workspace 01"
+}
+
+

Parameters

+ + + + + + + + + + + + + + + + + + + + +
NameInTypeRequiredDescription
bodybodyWorkspaceCreateInputtruenone
+
+

Example responses

+

201 Response

+
+
{
+  "description": "This is an example workspace",
+  "name": "Workspace 01"
+}
+
+

Responses

+ + + + + + + + + + + + + + + + + + + + + + + + +
StatusMeaningDescriptionSchema
201CreatedCreated workspacesWorkspaceCreateOutput
422Unprocessable EntityValidation ErrorHTTPValidationError
+ + +

get_workspace_permissions_workspaces_permissions_get

+

+
+

Code samples

+
+

GET /workspaces/permissions

+

Get Workspace Permissions

+
+

Example responses

+

200 Response

+
+
{
+  "permissions": [
+    "get_workspaces",
+    "create_workspace",
+    "get_workspace",
+    "update_workspace",
+    "delete_workspace",
+    "get_workspace_members",
+    "add_workspace_members",
+    "remove_workspace_member",
+    "get_groups",
+    "create_group",
+    "get_workspace_policies",
+    "get_workspace_policy",
+    "set_workspace_policy",
+    "get_workspace_permissions"
+  ]
+}
+
+

Responses

+ + + + + + + + + + + + + + + + + + +
StatusMeaningDescriptionSchema
200OKList of all workspace permissionsPermissionList
+ + +

get_workspace_workspaces__workspace_id__get

+

+
+

Code samples

+
+

GET /workspaces/{workspace_id}

+

Get Workspace

+

Description:

+

Endpoint to get a workspace with the given id. +By default, it returns the basic information of the workspace such as id, name, and description. +The user can specify other resources to include in the response using the query parameters.

+

For example, to include groups and members in the response, the user can send the following GET request:

+
+

/workspaces/6497fdbafe12e8ff9017f253?include=groups&include=members

+
+

To include all resources, the user can send the following GET request:

+
+

/workspaces/6497fdbafe12e8ff9017f253?include=all

+
+

To get basic information of the workspace, the user can send the following GET request:

+
+

/workspaces/6497fdbafe12e8ff9017f253

+
+

Path parameters:

+
    +
  • workspace_id (str): id of the workspace
  • +
+

Query parameters:

+
    +
  • +

    include (str): resources to include in the response

    +

    Possible values:

    +
      +
    • groups: include groups in the response
    • +
    • members: include members in the response
    • +
    • policies: include policies in the response
    • +
    • all: include all resources in the response
    • +
    +
  • +
+

Response:

+

Returns a workspace with the given id.

+

Parameters

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameInTypeRequiredDescription
workspace_idpathstringtruenone
includequeryanyfalsenone
+
+

Example responses

+

200 Response

+
+
{
+  "description": "This is an example workspace",
+  "id": "1a2b3c4d5e6f7g8h9i0j",
+  "name": "Workspace 01"
+}
+
+

Responses

+ + + + + + + + + + + + + + + + + + + + + + + + +
StatusMeaningDescriptionSchema
200OKWorkspace dataWorkspace
422Unprocessable EntityValidation ErrorHTTPValidationError
+ + +

update_workspace_workspaces__workspace_id__patch

+

+
+

Code samples

+
+

PATCH /workspaces/{workspace_id}

+

Update Workspace

+

Updates the workspace with the given id. +Query parameters: + @param workspace_id: id of the workspace to update +Body parameters: +- name (str): name of the workspace, must be unique +- description (str): description of the workspace

+

Returns the updated workspace.

+
+

Body parameter

+
+
{
+  "description": "This is an example workspace",
+  "name": "Workspace 01"
+}
+
+

Parameters

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameInTypeRequiredDescription
workspace_idpathstringtruenone
bodybodyWorkspaceUpdateRequesttruenone
+
+

Example responses

+

200 Response

+
+
{
+  "description": "This is an example workspace",
+  "id": "1a2b3c4d5e6f7g8h9i0j",
+  "name": "Workspace 01"
+}
+
+

Responses

+ + + + + + + + + + + + + + + + + + + + + + + + +
StatusMeaningDescriptionSchema
200OKUpdated workspaceWorkspace
422Unprocessable EntityValidation ErrorHTTPValidationError
+ + +

delete_workspace_workspaces__workspace_id__delete

+

+
+

Code samples

+
+

DELETE /workspaces/{workspace_id}

+

Delete Workspace

+

Deletes the workspace with the given id. +Query parameters: + @param workspace_id: id of the workspace to delete

+

Returns status code 204 if the workspace is deleted successfully. +Response has no detail.

+

Parameters

+ + + + + + + + + + + + + + + + + + + + +
NameInTypeRequiredDescription
workspace_idpathstringtruenone
+
+

Example responses

+

422 Response

+
+
{
+  "detail": [
+    {
+      "loc": [
+        "string"
+      ],
+      "msg": "string",
+      "type": "string"
+    }
+  ]
+}
+
+

Responses

+ + + + + + + + + + + + + + + + + + + + + + + + +
StatusMeaningDescriptionSchema
204No ContentDeleted workspaceNone
422Unprocessable EntityValidation ErrorHTTPValidationError
+ + +

get_groups_workspaces__workspace_id__groups_get

+

+
+

Code samples

+
+

GET /workspaces/{workspace_id}/groups

+

Get Groups

+

Parameters

+ + + + + + + + + + + + + + + + + + + + +
NameInTypeRequiredDescription
workspace_idpathstringtruenone
+
+

Example responses

+

200 Response

+
+
{
+  "groups": [
+    {
+      "id": "5eb7cf5a86d9755df3a6c593",
+      "name": "string",
+      "description": "string"
+    }
+  ]
+}
+
+

Responses

+ + + + + + + + + + + + + + + + + + + + + + + + +
StatusMeaningDescriptionSchema
200OKList of all groupsGroupList
422Unprocessable EntityValidation ErrorHTTPValidationError
+ + +

create_group_workspaces__workspace_id__groups_post

+

+
+

Code samples

+
+

POST /workspaces/{workspace_id}/groups

+

Create Group

+
+

Body parameter

+
+
{
+  "description": "My first Group",
+  "name": "Group 01"
+}
+
+

Parameters

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameInTypeRequiredDescription
workspace_idpathstringtruenone
bodybodyGroupCreateInputtruenone
+
+

Example responses

+

201 Response

+
+
{
+  "id": "5eb7cf5a86d9755df3a6c593",
+  "name": "string",
+  "description": "string"
+}
+
+

Responses

+ + + + + + + + + + + + + + + + + + + + + + + + +
StatusMeaningDescriptionSchema
201CreatedCreated GroupGroupCreateOutput
422Unprocessable EntityValidation ErrorHTTPValidationError
+ + +

get_workspace_members_workspaces__workspace_id__members_get

+

+
+

Code samples

+
+

GET /workspaces/{workspace_id}/members

+

Get Workspace Members

+

Parameters

+ + + + + + + + + + + + + + + + + + + + +
NameInTypeRequiredDescription
workspace_idpathstringtruenone
+
+

Example responses

+

200 Response

+
+
{
+  "members": [
+    {
+      "email": "jdoe@example.com",
+      "first_name": "John",
+      "last_name": "Doe",
+      "role": "admin"
+    },
+    {
+      "email": "jsmith@example.com",
+      "first_name": "Jack",
+      "last_name": "Smith",
+      "role": "user"
+    }
+  ]
+}
+
+

Responses

+ + + + + + + + + + + + + + + + + + + + + + + + +
StatusMeaningDescriptionSchema
200OKList of all groupsMemberList
422Unprocessable EntityValidation ErrorHTTPValidationError
+ + +

add_workspace_members_workspaces__workspace_id__members_post

+

+
+

Code samples

+
+

POST /workspaces/{workspace_id}/members

+

Add Workspace Members

+
+

Body parameter

+
+
{
+  "accounts": [
+    "1a2b3c4d5e6f7g8h9i0j",
+    "2a3b4c5d6e7f8g9h0i1j",
+    "3a4b5c6d7e8f9g0h1i2j"
+  ]
+}
+
+

Parameters

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameInTypeRequiredDescription
workspace_idpathstringtruenone
bodybodyAddMemberstruenone
+
+

Example responses

+

200 Response

+
+
{
+  "members": [
+    {
+      "email": "jdoe@example.com",
+      "first_name": "John",
+      "last_name": "Doe",
+      "role": "admin"
+    },
+    {
+      "email": "jsmith@example.com",
+      "first_name": "Jack",
+      "last_name": "Smith",
+      "role": "user"
+    }
+  ]
+}
+
+

Responses

+ + + + + + + + + + + + + + + + + + + + + + + + +
StatusMeaningDescriptionSchema
200OKList added membersMemberList
422Unprocessable EntityValidation ErrorHTTPValidationError
+ + +

remove_workspace_member_workspaces__workspace_id__members__account_id__delete

+

+
+

Code samples

+
+

DELETE /workspaces/{workspace_id}/members/{account_id}

+

Remove Workspace Member

+

Parameters

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameInTypeRequiredDescription
workspace_idpathstringtruenone
account_idpathstringtruenone
+
+

Example responses

+

200 Response

+
+
null
+
+

Responses

+ + + + + + + + + + + + + + + + + + + + + + + + +
StatusMeaningDescriptionSchema
200OKUpdated list removed membersInline
422Unprocessable EntityValidation ErrorHTTPValidationError
+

Response Schema

+ + + +

get_workspace_policies_workspaces__workspace_id__policies_get

+

+
+

Code samples

+
+

GET /workspaces/{workspace_id}/policies

+

Get Workspace Policies

+

Parameters

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameInTypeRequiredDescription
workspace_idpathstringtruenone
account_idquerystringfalsenone
+
+

Example responses

+

200 Response

+
+
{
+  "policies": [
+    {
+      "permissions": [
+        "get_workspace",
+        "get_groups"
+      ],
+      "policy_holder": {
+        "email": "email@example.com",
+        "first_name": "Name",
+        "id": "1a2b3c4d5e6f7g8h9i0j",
+        "last_name": "Surname"
+      }
+    },
+    {
+      "permissions": [
+        "get_workspace",
+        "get_groups"
+      ],
+      "policy_holder": {
+        "email": "email@example.com",
+        "first_name": "Name",
+        "id": "1a2b3c4d5e6f7g8h9i0j",
+        "last_name": "Surname"
+      }
+    }
+  ]
+}
+
+

Responses

+ + + + + + + + + + + + + + + + + + + + + + + + +
StatusMeaningDescriptionSchema
200OKList of all policiesPolicyList
422Unprocessable EntityValidation ErrorHTTPValidationError
+ + +

set_workspace_policy_workspaces__workspace_id__policies__policy_id__put

+

+
+

Code samples

+
+

PUT /workspaces/{workspace_id}/policies/{policy_id}

+

Set Workspace Policy

+

Sets the permissions for a user in a workspace. +Query parameters: + @param workspace_id: id of the workspace to update +Body parameters: +- user_id (str): id of the user to update +- permissions (int): new permissions for the user

+

Returns the updated workspace.

+
+

Body parameter

+
+
{
+  "permissions": [
+    "get_workspace_info",
+    "list_members"
+  ]
+}
+
+

Parameters

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameInTypeRequiredDescription
workspace_idpathstringtruenone
policy_idpathstringtruenone
bodybodyPolicyInputtruenone
+
+

Example responses

+

200 Response

+
+
{
+  "permissions": [
+    "get_workspaces",
+    "create_workspace",
+    "get_workspace",
+    "update_workspace",
+    "delete_workspace",
+    "get_workspace_members",
+    "add_workspace_members",
+    "remove_workspace_member",
+    "get_groups",
+    "create_group",
+    "get_all_workspace_policies",
+    "get_workspace_policy",
+    "set_workspace_policy"
+  ],
+  "policy_holder": {
+    "email": "email@example.com",
+    "first_name": "Name",
+    "id": "1a2b3c4d5e6f7g8h9i0j",
+    "last_name": "Surname"
+  }
+}
+
+

Responses

+ + + + + + + + + + + + + + + + + + + + + + + + +
StatusMeaningDescriptionSchema
200OKUpdated permissionsPolicyOutput
422Unprocessable EntityValidation ErrorHTTPValidationError
+ + +

get_polls_workspaces__workspace_id__polls_get

+

+
+

Code samples

+
+

GET /workspaces/{workspace_id}/polls

+

Get Polls

+

Parameters

+ + + + + + + + + + + + + + + + + + + + +
NameInTypeRequiredDescription
workspace_idpathstringtruenone
+
+

Example responses

+

200 Response

+
+
{
+  "polls": [
+    {
+      "description": "This is an example poll",
+      "id": "1a2b3c4d5e6f7g8h9i0j",
+      "name": "Poll 01",
+      "published": true
+    },
+    {
+      "description": "This is an example poll",
+      "id": "1a2b3c4d5e6f7g8h9i0j",
+      "name": "Poll 02",
+      "published": true
+    }
+  ]
+}
+
+

Responses

+ + + + + + + + + + + + + + + + + + + + + + + + +
StatusMeaningDescriptionSchema
200OKList of all polls in the workspacePollList
422Unprocessable EntityValidation ErrorHTTPValidationError
+ + +

create_poll_workspaces__workspace_id__polls_post

+

+
+

Code samples

+
+

POST /workspaces/{workspace_id}/polls

+

Create Poll

+
+

Body parameter

+
+
{
+  "name": "string",
+  "description": "string",
+  "public": true,
+  "published": true,
+  "questions": [
+    {
+      "id": 0,
+      "question": "string",
+      "question_type": "string",
+      "options": [
+        "string"
+      ],
+      "correct_answer": [
+        0
+      ]
+    }
+  ]
+}
+
+

Parameters

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameInTypeRequiredDescription
workspace_idpathstringtruenone
bodybodyCreatePollRequesttruenone
+
+

Example responses

+

201 Response

+
+
{
+  "description": "This is an example poll",
+  "id": "1a2b3c4d5e6f7g8h9i0j",
+  "name": "Poll 01",
+  "published": true
+}
+
+

Responses

+ + + + + + + + + + + + + + + + + + + + + + + + +
StatusMeaningDescriptionSchema
201CreatedCreated pollPollResponse
422Unprocessable EntityValidation ErrorHTTPValidationError
+ + +

Groups

+ +

get_all_groups_groups__get

+

+
+

Code samples

+
+

GET /groups/

+

Get All Groups

+

Parameters

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameInTypeRequiredDescription
workspacequeryanyfalsenone
accountqueryanyfalsenone
namequeryanyfalsenone
+
+

Example responses

+

200 Response

+
+
{
+  "groups": [
+    {
+      "id": "5eb7cf5a86d9755df3a6c593",
+      "name": "string",
+      "description": "string"
+    }
+  ]
+}
+
+

Responses

+ + + + + + + + + + + + + + + + + + + + + + + + +
StatusMeaningDescriptionSchema
200OKList of groupsGroupList
422Unprocessable EntityValidation ErrorHTTPValidationError
+ + +

create_group_groups__post

+

+
+

Code samples

+
+

POST /groups/

+

Create Group

+
+

Body parameter

+
+
{
+  "description": "My first Group",
+  "name": "Group 01",
+  "workspace": "60b9d1c8e1f1d5f5f5b4f8e1"
+}
+
+

Parameters

+ + + + + + + + + + + + + + + + + + + + +
NameInTypeRequiredDescription
bodybodyGroupCreateRequesttruenone
+
+

Example responses

+

201 Response

+
+
{
+  "id": "5eb7cf5a86d9755df3a6c593",
+  "name": "string",
+  "description": "string"
+}
+
+

Responses

+ + + + + + + + + + + + + + + + + + + + + + + + +
StatusMeaningDescriptionSchema
201CreatedCreated GroupGroupCreateOutput
422Unprocessable EntityValidation ErrorHTTPValidationError
+ + +

get_group_permissions_groups_permissions_get

+

+
+

Code samples

+
+

GET /groups/permissions

+

Get Group Permissions

+
+

Example responses

+

200 Response

+
+
{
+  "permissions": [
+    "get_workspaces",
+    "create_workspace",
+    "get_workspace",
+    "update_workspace",
+    "delete_workspace",
+    "get_workspace_members",
+    "add_workspace_members",
+    "remove_workspace_member",
+    "get_groups",
+    "create_group",
+    "get_workspace_policies",
+    "get_workspace_policy",
+    "set_workspace_policy",
+    "get_workspace_permissions"
+  ]
+}
+
+

Responses

+ + + + + + + + + + + + + + + + + + +
StatusMeaningDescriptionSchema
200OKList of all Group permissionsPermissionList
+ + +

get_group_groups__group_id__get

+

+
+

Code samples

+
+

GET /groups/{group_id}

+

Get Group

+

Parameters

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameInTypeRequiredDescription
group_idpathstringtruenone
includequeryanyfalsenone
+
+

Example responses

+

200 Response

+
+
{
+  "id": "5eb7cf5a86d9755df3a6c593",
+  "name": "string",
+  "description": "string",
+  "workspace": {},
+  "members": [
+    null
+  ],
+  "policies": [
+    null
+  ]
+}
+
+

Responses

+ + + + + + + + + + + + + + + + + + + + + + + + +
StatusMeaningDescriptionSchema
200OKGet a groupGroup
422Unprocessable EntityValidation ErrorHTTPValidationError
+ + +

update_group_groups__group_id__patch

+

+
+

Code samples

+
+

PATCH /groups/{group_id}

+

Update Group

+
+

Body parameter

+
+
{
+  "Description": "Updated description"
+}
+
+

Parameters

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameInTypeRequiredDescription
group_idpathstringtruenone
bodybodyGroupUpdateRequesttruenone
+
+

Example responses

+

200 Response

+
+
{
+  "id": "5eb7cf5a86d9755df3a6c593",
+  "name": "string",
+  "description": "string"
+}
+
+

Responses

+ + + + + + + + + + + + + + + + + + + + + + + + +
StatusMeaningDescriptionSchema
200OKUpdate a groupGroupShort
422Unprocessable EntityValidation ErrorHTTPValidationError
+ + +

delete_group_groups__group_id__delete

+

+
+

Code samples

+
+

DELETE /groups/{group_id}

+

Delete Group

+

Parameters

+ + + + + + + + + + + + + + + + + + + + +
NameInTypeRequiredDescription
group_idpathstringtruenone
+
+

Example responses

+

422 Response

+
+
{
+  "detail": [
+    {
+      "loc": [
+        "string"
+      ],
+      "msg": "string",
+      "type": "string"
+    }
+  ]
+}
+
+

Responses

+ + + + + + + + + + + + + + + + + + + + + + + + +
StatusMeaningDescriptionSchema
204No ContentDelete a groupNone
422Unprocessable EntityValidation ErrorHTTPValidationError
+ + +

get_group_members_groups__group_id__members_get

+

+
+

Code samples

+
+

GET /groups/{group_id}/members

+

Get Group Members

+

Parameters

+ + + + + + + + + + + + + + + + + + + + +
NameInTypeRequiredDescription
group_idpathstringtruenone
+
+

Example responses

+

200 Response

+
+
{
+  "members": [
+    {
+      "email": "jdoe@example.com",
+      "first_name": "John",
+      "last_name": "Doe",
+      "role": "admin"
+    },
+    {
+      "email": "jsmith@example.com",
+      "first_name": "Jack",
+      "last_name": "Smith",
+      "role": "user"
+    }
+  ]
+}
+
+

Responses

+ + + + + + + + + + + + + + + + + + + + + + + + +
StatusMeaningDescriptionSchema
200OKList of group membersMemberList
422Unprocessable EntityValidation ErrorHTTPValidationError
+ + +

add_group_members_groups__group_id__members_post

+

+
+

Code samples

+
+

POST /groups/{group_id}/members

+

Add Group Members

+
+

Body parameter

+
+
{
+  "accounts": [
+    "1a2b3c4d5e6f7g8h9i0j",
+    "2a3b4c5d6e7f8g9h0i1j",
+    "3a4b5c6d7e8f9g0h1i2j"
+  ]
+}
+
+

Parameters

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameInTypeRequiredDescription
group_idpathstringtruenone
bodybodyAddMemberstruenone
+
+

Example responses

+

200 Response

+
+
{
+  "members": [
+    {
+      "email": "jdoe@example.com",
+      "first_name": "John",
+      "last_name": "Doe",
+      "role": "admin"
+    },
+    {
+      "email": "jsmith@example.com",
+      "first_name": "Jack",
+      "last_name": "Smith",
+      "role": "user"
+    }
+  ]
+}
+
+

Responses

+ + + + + + + + + + + + + + + + + + + + + + + + +
StatusMeaningDescriptionSchema
200OKList of group membersMemberList
422Unprocessable EntityValidation ErrorHTTPValidationError
+ + +

remove_group_member_groups__group_id__members__account_id__delete

+

+
+

Code samples

+
+

DELETE /groups/{group_id}/members/{account_id}

+

Remove Group Member

+

Parameters

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameInTypeRequiredDescription
group_idpathstringtruenone
account_idpathstringtruenone
+
+

Example responses

+

200 Response

+
+
null
+
+

Responses

+ + + + + + + + + + + + + + + + + + + + + + + + +
StatusMeaningDescriptionSchema
200OKUpdated list removed membersInline
422Unprocessable EntityValidation ErrorHTTPValidationError
+

Response Schema

+ + + +

get_group_policies_groups__group_id__policies_get

+

+
+

Code samples

+
+

GET /groups/{group_id}/policies

+

Get Group Policies

+

Parameters

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameInTypeRequiredDescription
group_idpathstringtruenone
account_idquerystringfalsenone
+
+

Example responses

+

200 Response

+
+
{
+  "policies": [
+    {
+      "permissions": [
+        "get_workspace",
+        "get_groups"
+      ],
+      "policy_holder": {
+        "email": "email@example.com",
+        "first_name": "Name",
+        "id": "1a2b3c4d5e6f7g8h9i0j",
+        "last_name": "Surname"
+      }
+    },
+    {
+      "permissions": [
+        "get_workspace",
+        "get_groups"
+      ],
+      "policy_holder": {
+        "email": "email@example.com",
+        "first_name": "Name",
+        "id": "1a2b3c4d5e6f7g8h9i0j",
+        "last_name": "Surname"
+      }
+    }
+  ]
+}
+
+

Responses

+ + + + + + + + + + + + + + + + + + + + + + + + +
StatusMeaningDescriptionSchema
200OKList of all policiesPolicyList
422Unprocessable EntityValidation ErrorHTTPValidationError
+ + +

set_group_policy_groups__group_id__policies__policy_id__put

+

+
+

Code samples

+
+

PUT /groups/{group_id}/policies/{policy_id}

+

Set Group Policy

+

Sets the permissions for a user in a workspace. +Query parameters: + @param workspace_id: id of the workspace to update +Body parameters: +- user_id (str): id of the user to update +- permissions (int): new permissions for the user

+
+

Body parameter

+
+
{
+  "permissions": [
+    "get_workspace_info",
+    "list_members"
+  ]
+}
+
+

Parameters

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameInTypeRequiredDescription
group_idpathstringtruenone
policy_idpathstringtruenone
bodybodyPolicyInputtruenone
+
+

Example responses

+

200 Response

+
+
{
+  "permissions": [
+    "get_workspaces",
+    "create_workspace",
+    "get_workspace",
+    "update_workspace",
+    "delete_workspace",
+    "get_workspace_members",
+    "add_workspace_members",
+    "remove_workspace_member",
+    "get_groups",
+    "create_group",
+    "get_all_workspace_policies",
+    "get_workspace_policy",
+    "set_workspace_policy"
+  ],
+  "policy_holder": {
+    "email": "email@example.com",
+    "first_name": "Name",
+    "id": "1a2b3c4d5e6f7g8h9i0j",
+    "last_name": "Surname"
+  }
+}
+
+

Responses

+ + + + + + + + + + + + + + + + + + + + + + + + +
StatusMeaningDescriptionSchema
200OKUpdated policyPolicyOutput
422Unprocessable EntityValidation ErrorHTTPValidationError
+ + +

Polls

+ +

get_poll_polls__poll_id__get

+

+
+

Code samples

+
+

GET /polls/{poll_id}

+

Get Poll

+

Parameters

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameInTypeRequiredDescription
poll_idpathstringtruenone
includequeryanyfalsenone
+
+

Example responses

+

200 Response

+
+
{
+  "description": "This is an example poll",
+  "id": "1a2b3c4d5e6f7g8h9i0j",
+  "name": "Poll 01",
+  "published": true
+}
+
+

Responses

+ + + + + + + + + + + + + + + + + + + + + + + + +
StatusMeaningDescriptionSchema
200OKPoll detailsPollResponse
422Unprocessable EntityValidation ErrorHTTPValidationError
+ + +

update_poll_polls__poll_id__patch

+

+
+

Code samples

+
+

PATCH /polls/{poll_id}

+

Update Poll

+
+

Body parameter

+
+
{
+  "description": "This is an example poll",
+  "name": "Poll 01",
+  "published": true
+}
+
+

Parameters

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameInTypeRequiredDescription
poll_idpathstringtruenone
bodybodyUpdatePollRequesttruenone
+
+

Example responses

+

200 Response

+
+
{
+  "description": "This is an example poll",
+  "id": "1a2b3c4d5e6f7g8h9i0j",
+  "name": "Poll 01",
+  "published": true
+}
+
+

Responses

+ + + + + + + + + + + + + + + + + + + + + + + + +
StatusMeaningDescriptionSchema
200OKUpdate Poll detailPollResponse
422Unprocessable EntityValidation ErrorHTTPValidationError
+ + +

delete_poll_polls__poll_id__delete

+

+
+

Code samples

+
+

DELETE /polls/{poll_id}

+

Delete Poll

+

Parameters

+ + + + + + + + + + + + + + + + + + + + +
NameInTypeRequiredDescription
poll_idpathstringtruenone
+
+

Example responses

+

422 Response

+
+
{
+  "detail": [
+    {
+      "loc": [
+        "string"
+      ],
+      "msg": "string",
+      "type": "string"
+    }
+  ]
+}
+
+

Responses

+ + + + + + + + + + + + + + + + + + + + + + + + +
StatusMeaningDescriptionSchema
204No ContentResult of delete operationNone
422Unprocessable EntityValidation ErrorHTTPValidationError
+ + +

get_questions_polls__poll_id__questions_get

+

+
+

Code samples

+
+

GET /polls/{poll_id}/questions

+

Get Questions

+

Parameters

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameInTypeRequiredDescription
poll_idpathstringtruenone
includequeryanyfalsenone
+
+

Example responses

+

200 Response

+
+
{
+  "questions": [
+    {
+      "id": 0,
+      "question": "string",
+      "question_type": "string",
+      "options": [
+        "string"
+      ],
+      "correct_answer": [
+        0
+      ]
+    }
+  ]
+}
+
+

Responses

+ + + + + + + + + + + + + + + + + + + + + + + + +
StatusMeaningDescriptionSchema
200OKQuestions in a pollQuestionList
422Unprocessable EntityValidation ErrorHTTPValidationError
+ + +

get_policies_polls__poll_id__policies_get

+

+
+

Code samples

+
+

GET /polls/{poll_id}/policies

+

Get Policies

+

Parameters

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameInTypeRequiredDescription
poll_idpathstringtruenone
includequeryanyfalsenone
+
+

Example responses

+

200 Response

+
+
{
+  "policies": [
+    {
+      "permissions": [
+        "get_workspace",
+        "get_groups"
+      ],
+      "policy_holder": {
+        "email": "email@example.com",
+        "first_name": "Name",
+        "id": "1a2b3c4d5e6f7g8h9i0j",
+        "last_name": "Surname"
+      }
+    },
+    {
+      "permissions": [
+        "get_workspace",
+        "get_groups"
+      ],
+      "policy_holder": {
+        "email": "email@example.com",
+        "first_name": "Name",
+        "id": "1a2b3c4d5e6f7g8h9i0j",
+        "last_name": "Surname"
+      }
+    }
+  ]
+}
+
+

Responses

+ + + + + + + + + + + + + + + + + + + + + + + + +
StatusMeaningDescriptionSchema
200OKPolicy list of a pollPolicyList
422Unprocessable EntityValidation ErrorHTTPValidationError
+ + +

Accounts

+ +

get_all_accounts_accounts_get

+

+
+

Code samples

+
+

GET /accounts

+

Get All Accounts

+
+

Example responses

+

200 Response

+
+
{
+  "accounts": [
+    {
+      "id": "5eb7cf5a86d9755df3a6c593",
+      "email": "user@example.com",
+      "first_name": "string",
+      "last_name": "string"
+    }
+  ]
+}
+
+

Responses

+ + + + + + + + + + + + + + + + + + +
StatusMeaningDescriptionSchema
200OKSuccessful ResponseAccountList
+ + +

users_current_user_accounts_me_get

+

+
+

Code samples

+
+

GET /accounts/me

+

Users:Current User

+
+

Example responses

+

200 Response

+
+
{
+  "email": "user@example.com",
+  "first_name": "John",
+  "last_name": "Smith",
+  "password": "pass1234"
+}
+
+

Responses

+ + + + + + + + + + + + + + + + + + + + + + + + +
StatusMeaningDescriptionSchema
200OKSuccessful ResponseAccount
401UnauthorizedMissing token or inactive user.None
+ + +

delete_my_account_accounts_me_delete

+

+
+

Code samples

+
+

DELETE /accounts/me

+

Delete My Account

+

Delete current user account

+

This route deletes the account of the currently logged in user.

+

Request body

+
    +
  • user - User object
  • +
+

Expected Response

+

204 - The account has been deleted

+

Responses

+ + + + + + + + + + + + + + + + + + +
StatusMeaningDescriptionSchema
204No ContentSuccessful ResponseNone
+ + +

users_patch_current_user_accounts_me_patch

+

+
+

Code samples

+
+

PATCH /accounts/me

+

Users:Patch Current User

+
+

Body parameter

+
+
{
+  "email": "user@example.com",
+  "first_name": "John",
+  "last_name": "Smith",
+  "password": "pass1234"
+}
+
+

Parameters

+ + + + + + + + + + + + + + + + + + + + +
NameInTypeRequiredDescription
bodybodyUpdateAccounttruenone
+
+

Example responses

+

200 Response

+
+
{
+  "email": "user@example.com",
+  "first_name": "John",
+  "last_name": "Smith",
+  "password": "pass1234"
+}
+
+
+

Bad Request

+
+
{
+  "detail": "UPDATE_USER_EMAIL_ALREADY_EXISTS"
+}
+
+
{
+  "detail": {
+    "code": "UPDATE_USER_INVALID_PASSWORD",
+    "reason": "Password should beat least 3 characters"
+  }
+}
+
+

Responses

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
StatusMeaningDescriptionSchema
200OKSuccessful ResponseAccount
400Bad RequestBad RequestErrorModel
401UnauthorizedMissing token or inactive user.None
422Unprocessable EntityValidation ErrorHTTPValidationError
+ + +

users_delete_user_accounts__id__delete

+

+
+

Code samples

+
+

DELETE /accounts/{id}

+

Users:Delete User

+

Parameters

+ + + + + + + + + + + + + + + + + + + + +
NameInTypeRequiredDescription
idpathstringtruenone
+
+

Example responses

+

422 Response

+
+
{
+  "detail": [
+    {
+      "loc": [
+        "string"
+      ],
+      "msg": "string",
+      "type": "string"
+    }
+  ]
+}
+
+

Responses

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
StatusMeaningDescriptionSchema
204No ContentSuccessful ResponseNone
401UnauthorizedMissing token or inactive user.None
403ForbiddenNot a superuser.None
404Not FoundThe user does not exist.None
422Unprocessable EntityValidation ErrorHTTPValidationError
+ + +

users_user_accounts__id__get

+

+
+

Code samples

+
+

GET /accounts/{id}

+

Users:User

+

Parameters

+ + + + + + + + + + + + + + + + + + + + +
NameInTypeRequiredDescription
idpathstringtruenone
+
+

Example responses

+

200 Response

+
+
{
+  "email": "user@example.com",
+  "first_name": "John",
+  "last_name": "Smith",
+  "password": "pass1234"
+}
+
+

Responses

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
StatusMeaningDescriptionSchema
200OKSuccessful ResponseAccount
401UnauthorizedMissing token or inactive user.None
403ForbiddenNot a superuser.None
404Not FoundThe user does not exist.None
422Unprocessable EntityValidation ErrorHTTPValidationError
+ + +

users_patch_user_accounts__id__patch

+

+
+

Code samples

+
+

PATCH /accounts/{id}

+

Users:Patch User

+
+

Body parameter

+
+
{
+  "email": "user@example.com",
+  "first_name": "John",
+  "last_name": "Smith",
+  "password": "pass1234"
+}
+
+

Parameters

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameInTypeRequiredDescription
idpathstringtruenone
bodybodyUpdateAccounttruenone
+
+

Example responses

+

200 Response

+
+
{
+  "email": "user@example.com",
+  "first_name": "John",
+  "last_name": "Smith",
+  "password": "pass1234"
+}
+
+
+

Bad Request

+
+
{
+  "detail": "UPDATE_USER_EMAIL_ALREADY_EXISTS"
+}
+
+
{
+  "detail": {
+    "code": "UPDATE_USER_INVALID_PASSWORD",
+    "reason": "Password should beat least 3 characters"
+  }
+}
+
+

Responses

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
StatusMeaningDescriptionSchema
200OKSuccessful ResponseAccount
400Bad RequestBad RequestErrorModel
401UnauthorizedMissing token or inactive user.None
403ForbiddenNot a superuser.None
404Not FoundThe user does not exist.None
422Unprocessable EntityValidation ErrorHTTPValidationError
+ + +

Authentication

+ +

auth_token_login_auth_jwt_login_post

+

+
+

Code samples

+
+

POST /auth/jwt/login

+

Auth:Token.Login

+
+

Body parameter

+
+
grant_type: string
+username: string
+password: string
+scope: ""
+client_id: string
+client_secret: string
+
+

Parameters

+ + + + + + + + + + + + + + + + + + + + +
NameInTypeRequiredDescription
bodybodyBody_auth_token_login_auth_jwt_login_posttruenone
+
+

Example responses

+

200 Response

+
+
{
+  "access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoiOTIyMWZmYzktNjQwZi00MzcyLTg2ZDMtY2U2NDJjYmE1NjAzIiwiYXVkIjoiZmFzdGFwaS11c2VyczphdXRoIiwiZXhwIjoxNTcxNTA0MTkzfQ.M10bjOe45I5Ncu_uXvOmVV8QxnL-nZfcH96U90JaocI",
+  "refresh_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoiOTIyMWZmYzktNjQwZi00MzcyLTg2ZDMtY2U2NDJjYmE1NjAzIiwiYXVkIjoiZmFzdGFwaS11c2VyczphdXRoIiwiZXhwIjoxNTcxNTA0MTkzfQ.M10bjOe45I5Ncu_uXvOmVV8QxnL-nZfcH96U90JaocI",
+  "token_type": "bearer",
+  "expires_in": 3600
+}
+
+
+

Bad Request

+
+
{
+  "detail": "LOGIN_BAD_CREDENTIALS"
+}
+
+
{
+  "detail": "LOGIN_USER_NOT_VERIFIED"
+}
+
+
+

422 Response

+
+
{
+  "detail": [
+    {
+      "loc": [
+        "string"
+      ],
+      "msg": "string",
+      "type": "string"
+    }
+  ]
+}
+
+

Responses

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
StatusMeaningDescriptionSchema
200OKSuccessful ResponseLoginResponse
400Bad RequestBad RequestErrorModel
422Unprocessable EntityValidation ErrorHTTPValidationError
+ + +

refresh_jwt_auth_jwt_refresh_post

+

+
+

Code samples

+
+

POST /auth/jwt/refresh

+

Refresh Jwt

+

Refresh the access token using the refresh token.

+

Headers: + authorization: Authorization header with the access token + refresh_token: Refresh-Token header with the refresh token

+

Parameters

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameInTypeRequiredDescription
authorizationheaderstringtruenone
refresh-tokenheaderstringtruenone
+
+

Example responses

+

200 Response

+
+
{
+  "access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoiOTIyMWZmYzktNjQwZi00MzcyLTg2ZDMtY2U2NDJjYmE1NjAzIiwiYXVkIjoiZmFzdGFwaS11c2VyczphdXRoIiwiZXhwIjoxNTcxNTA0MTkzfQ.M10bjOe45I5Ncu_uXvOmVV8QxnL-nZfcH96U90JaocI",
+  "refresh_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoiOTIyMWZmYzktNjQwZi00MzcyLTg2ZDMtY2U2NDJjYmE1NjAzIiwiYXVkIjoiZmFzdGFwaS11c2VyczphdXRoIiwiZXhwIjoxNTcxNTA0MTkzfQ.M10bjOe45I5Ncu_uXvOmVV8QxnL-nZfcH96U90JaocI",
+  "token_type": "bearer",
+  "expires_in": 3600
+}
+
+
+

Bad Request

+
+
{
+  "detail": "LOGIN_BAD_CREDENTIALS"
+}
+
+
{
+  "detail": "LOGIN_USER_NOT_VERIFIED"
+}
+
+
+

422 Response

+
+
{
+  "detail": [
+    {
+      "loc": [
+        "string"
+      ],
+      "msg": "string",
+      "type": "string"
+    }
+  ]
+}
+
+

Responses

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
StatusMeaningDescriptionSchema
200OKSuccessful ResponseLoginResponse
400Bad RequestBad RequestErrorModel
422Unprocessable EntityValidation ErrorHTTPValidationError
+ + +

refresh_jwt_with_client_ID_auth_jwt_postman_refresh_post

+

+
+

Code samples

+
+

POST /auth/jwt/postman_refresh

+

Refresh Jwt With Client Id

+

Refresh the access token using the refresh token.

+

Headers: + authorization: Authorization header with the access token +Body: + refresh_token: Refresh-Token header with the refresh token

+
+

Body parameter

+
+
"string"
+
+

Parameters

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameInTypeRequiredDescription
authorizationheaderstringtruenone
bodybodystringtruenone
+
+

Example responses

+

200 Response

+
+
{
+  "access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoiOTIyMWZmYzktNjQwZi00MzcyLTg2ZDMtY2U2NDJjYmE1NjAzIiwiYXVkIjoiZmFzdGFwaS11c2VyczphdXRoIiwiZXhwIjoxNTcxNTA0MTkzfQ.M10bjOe45I5Ncu_uXvOmVV8QxnL-nZfcH96U90JaocI",
+  "refresh_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoiOTIyMWZmYzktNjQwZi00MzcyLTg2ZDMtY2U2NDJjYmE1NjAzIiwiYXVkIjoiZmFzdGFwaS11c2VyczphdXRoIiwiZXhwIjoxNTcxNTA0MTkzfQ.M10bjOe45I5Ncu_uXvOmVV8QxnL-nZfcH96U90JaocI",
+  "token_type": "bearer",
+  "expires_in": 3600
+}
+
+
+

Bad Request

+
+
{
+  "detail": "LOGIN_BAD_CREDENTIALS"
+}
+
+
{
+  "detail": "LOGIN_USER_NOT_VERIFIED"
+}
+
+
+

422 Response

+
+
{
+  "detail": [
+    {
+      "loc": [
+        "string"
+      ],
+      "msg": "string",
+      "type": "string"
+    }
+  ]
+}
+
+

Responses

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
StatusMeaningDescriptionSchema
200OKSuccessful ResponseLoginResponse
400Bad RequestBad RequestErrorModel
422Unprocessable EntityValidation ErrorHTTPValidationError
+ + +

register_register_auth_register_post

+

+
+

Code samples

+
+

POST /auth/register

+

Register:Register

+
+

Body parameter

+
+
{
+  "email": "user@example.com",
+  "first_name": "John",
+  "last_name": "Smith",
+  "password": "pass1234"
+}
+
+

Parameters

+ + + + + + + + + + + + + + + + + + + + +
NameInTypeRequiredDescription
bodybodyCreateAccounttruenone
+
+

Example responses

+

201 Response

+
+
{
+  "email": "user@example.com",
+  "first_name": "John",
+  "last_name": "Smith",
+  "password": "pass1234"
+}
+
+
+

Bad Request

+
+
{
+  "detail": "REGISTER_USER_ALREADY_EXISTS"
+}
+
+
{
+  "detail": {
+    "code": "REGISTER_INVALID_PASSWORD",
+    "reason": "Password should beat least 3 characters"
+  }
+}
+
+

Responses

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
StatusMeaningDescriptionSchema
201CreatedSuccessful ResponseAccount
400Bad RequestBad RequestErrorModel
422Unprocessable EntityValidation ErrorHTTPValidationError
+ + +

reset_forgot_password_auth_forgot_password_post

+

+
+

Code samples

+
+

POST /auth/forgot-password

+

Reset:Forgot Password

+
+

Body parameter

+
+
{
+  "email": "user@example.com"
+}
+
+

Parameters

+ + + + + + + + + + + + + + + + + + + + +
NameInTypeRequiredDescription
bodybodyBody_reset_forgot_password_auth_forgot_password_posttruenone
+
+

Example responses

+

202 Response

+
+
null
+
+

Responses

+ + + + + + + + + + + + + + + + + + + + + + + + +
StatusMeaningDescriptionSchema
202AcceptedSuccessful ResponseInline
422Unprocessable EntityValidation ErrorHTTPValidationError
+

Response Schema

+ + + +

reset_reset_password_auth_reset_password_post

+

+
+

Code samples

+
+

POST /auth/reset-password

+

Reset:Reset Password

+
+

Body parameter

+
+
{
+  "token": "string",
+  "password": "string"
+}
+
+

Parameters

+ + + + + + + + + + + + + + + + + + + + +
NameInTypeRequiredDescription
bodybodyBody_reset_reset_password_auth_reset_password_posttruenone
+
+

Example responses

+

200 Response

+
+
null
+
+
+

Bad Request

+
+
{
+  "detail": "RESET_PASSWORD_BAD_TOKEN"
+}
+
+
{
+  "detail": {
+    "code": "RESET_PASSWORD_INVALID_PASSWORD",
+    "reason": "Password should be at least 3 characters"
+  }
+}
+
+

Responses

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
StatusMeaningDescriptionSchema
200OKSuccessful ResponseInline
400Bad RequestBad RequestErrorModel
422Unprocessable EntityValidation ErrorHTTPValidationError
+

Response Schema

+ + + +

verify_request_token_auth_request_verify_token_post

+

+
+

Code samples

+
+

POST /auth/request-verify-token

+

Verify:Request-Token

+
+

Body parameter

+
+
{
+  "email": "user@example.com"
+}
+
+

Parameters

+ + + + + + + + + + + + + + + + + + + + +
NameInTypeRequiredDescription
bodybodyBody_verify_request_token_auth_request_verify_token_posttruenone
+
+

Example responses

+

202 Response

+
+
null
+
+

Responses

+ + + + + + + + + + + + + + + + + + + + + + + + +
StatusMeaningDescriptionSchema
202AcceptedSuccessful ResponseInline
422Unprocessable EntityValidation ErrorHTTPValidationError
+

Response Schema

+ + + +

verify_verify_auth_verify_post

+

+
+

Code samples

+
+

POST /auth/verify

+

Verify:Verify

+
+

Body parameter

+
+
{
+  "token": "string"
+}
+
+

Parameters

+ + + + + + + + + + + + + + + + + + + + +
NameInTypeRequiredDescription
bodybodyBody_verify_verify_auth_verify_posttruenone
+
+

Example responses

+

200 Response

+
+
{
+  "email": "user@example.com",
+  "first_name": "John",
+  "last_name": "Smith",
+  "password": "pass1234"
+}
+
+
+

Bad Request

+
+
{
+  "detail": "VERIFY_USER_BAD_TOKEN"
+}
+
+
{
+  "detail": "VERIFY_USER_ALREADY_VERIFIED"
+}
+
+

Responses

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
StatusMeaningDescriptionSchema
200OKSuccessful ResponseAccount
400Bad RequestBad RequestErrorModel
422Unprocessable EntityValidation ErrorHTTPValidationError
+ + +

Schemas

+

Account

+ +

+ + +

+
{
+  "email": "user@example.com",
+  "first_name": "John",
+  "last_name": "Smith",
+  "password": "pass1234"
+}
+
+

Account

+

Properties

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
idstringtruenonenone
emailstring(email)truenonenone
is_activebooleanfalsenonenone
is_superuserbooleanfalsenonenone
is_verifiedbooleanfalsenonenone
first_namestringfalsenonenone
last_namestringfalsenonenone
+

AccountList

+ +

+ + +

+
{
+  "accounts": [
+    {
+      "id": "5eb7cf5a86d9755df3a6c593",
+      "email": "user@example.com",
+      "first_name": "string",
+      "last_name": "string"
+    }
+  ]
+}
+
+

AccountList

+

Properties

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
accounts[AccountShort]truenonenone
+

AccountShort

+ +

+ + +

+
{
+  "id": "5eb7cf5a86d9755df3a6c593",
+  "email": "user@example.com",
+  "first_name": "string",
+  "last_name": "string"
+}
+
+

AccountShort

+

Properties

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
idstringtruenonenone
emailstring(email)truenonenone
first_namestringtruenonenone
last_namestringtruenonenone
+

AddMembers

+ +

+ + +

+
{
+  "accounts": [
+    "1a2b3c4d5e6f7g8h9i0j",
+    "2a3b4c5d6e7f8g9h0i1j",
+    "3a4b5c6d7e8f9g0h1i2j"
+  ]
+}
+
+

AddMembers

+

Properties

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
accounts[string]truenonenone
+

Body_auth_token_login_auth_jwt_login_post

+ +

+ + +

+
{
+  "grant_type": "string",
+  "username": "string",
+  "password": "string",
+  "scope": "",
+  "client_id": "string",
+  "client_secret": "string"
+}
+
+

Body_auth_token_login_auth_jwt_login_post

+

Properties

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
grant_typeanyfalsenonenone
+

anyOf

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
» anonymousstringfalsenonenone
+

or

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
» anonymousnullfalsenonenone
+

continued

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
usernamestringtruenonenone
passwordstringtruenonenone
scopestringfalsenonenone
client_idanyfalsenonenone
+

anyOf

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
» anonymousstringfalsenonenone
+

or

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
» anonymousnullfalsenonenone
+

continued

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
client_secretanyfalsenonenone
+

anyOf

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
» anonymousstringfalsenonenone
+

or

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
» anonymousnullfalsenonenone
+

Body_reset_forgot_password_auth_forgot_password_post

+ +

+ + +

+
{
+  "email": "user@example.com"
+}
+
+

Body_reset_forgot_password_auth_forgot_password_post

+

Properties

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
emailstring(email)truenonenone
+

Body_reset_reset_password_auth_reset_password_post

+ +

+ + +

+
{
+  "token": "string",
+  "password": "string"
+}
+
+

Body_reset_reset_password_auth_reset_password_post

+

Properties

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
tokenstringtruenonenone
passwordstringtruenonenone
+

Body_verify_request_token_auth_request_verify_token_post

+ +

+ + +

+
{
+  "email": "user@example.com"
+}
+
+

Body_verify_request_token_auth_request_verify_token_post

+

Properties

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
emailstring(email)truenonenone
+

Body_verify_verify_auth_verify_post

+ +

+ + +

+
{
+  "token": "string"
+}
+
+

Body_verify_verify_auth_verify_post

+

Properties

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
tokenstringtruenonenone
+

CreateAccount

+ +

+ + +

+
{
+  "email": "user@example.com",
+  "first_name": "John",
+  "last_name": "Smith",
+  "password": "pass1234"
+}
+
+

CreateAccount

+

Properties

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
emailstring(email)truenonenone
passwordstringtruenonenone
is_activeanyfalsenonenone
+

anyOf

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
» anonymousbooleanfalsenonenone
+

or

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
» anonymousnullfalsenonenone
+

continued

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
is_superuseranyfalsenonenone
+

anyOf

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
» anonymousbooleanfalsenonenone
+

or

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
» anonymousnullfalsenonenone
+

continued

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
is_verifiedanyfalsenonenone
+

anyOf

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
» anonymousbooleanfalsenonenone
+

or

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
» anonymousnullfalsenonenone
+

continued

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
first_namestringfalsenonenone
last_namestringfalsenonenone
+

CreatePollRequest

+ +

+ + +

+
{
+  "name": "string",
+  "description": "string",
+  "public": true,
+  "published": true,
+  "questions": [
+    {
+      "id": 0,
+      "question": "string",
+      "question_type": "string",
+      "options": [
+        "string"
+      ],
+      "correct_answer": [
+        0
+      ]
+    }
+  ]
+}
+
+

CreatePollRequest

+

Properties

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
namestringtruenonenone
descriptionstringtruenonenone
publicbooleantruenonenone
publishedbooleantruenonenone
questions[Question]truenonenone
+

ErrorModel

+ +

+ + +

+
{
+  "detail": "string"
+}
+
+

ErrorModel

+

Properties

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
detailanytruenonenone
+

anyOf

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
» anonymousstringfalsenonenone
+

or

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
» anonymousobjectfalsenonenone
»» additionalPropertiesstringfalsenonenone
+

Group

+ +

+ + +

+
{
+  "id": "5eb7cf5a86d9755df3a6c593",
+  "name": "string",
+  "description": "string",
+  "workspace": {},
+  "members": [
+    null
+  ],
+  "policies": [
+    null
+  ]
+}
+
+

Group

+

Properties

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
idanyfalsenonenone
+

anyOf

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
» anonymousstringfalsenonenone
+

or

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
» anonymousnullfalsenonenone
+

continued

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
nameanyfalsenonenone
+

anyOf

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
» anonymousstringfalsenonenone
+

or

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
» anonymousnullfalsenonenone
+

continued

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
descriptionanyfalsenonenone
+

anyOf

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
» anonymousstringfalsenonenone
+

or

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
» anonymousnullfalsenonenone
+

continued

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
workspaceanyfalsenonenone
+

anyOf

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
» anonymousanyfalsenonenone
+

or

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
» anonymousnullfalsenonenone
+

continued

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
membersanyfalsenonenone
+

anyOf

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
» anonymous[any]falsenonenone
+

or

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
» anonymousnullfalsenonenone
+

continued

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
policiesanyfalsenonenone
+

anyOf

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
» anonymous[any]falsenonenone
+

or

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
» anonymousnullfalsenonenone
+

GroupCreateInput

+ +

+ + +

+
{
+  "description": "My first Group",
+  "name": "Group 01"
+}
+
+

GroupCreateInput

+

Properties

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
namestringfalsenonenone
descriptionstringfalsenonenone
+

GroupCreateOutput

+ +

+ + +

+
{
+  "id": "5eb7cf5a86d9755df3a6c593",
+  "name": "string",
+  "description": "string"
+}
+
+

GroupCreateOutput

+

Properties

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
idstringtruenonenone
namestringtruenonenone
descriptionstringtruenonenone
+

GroupCreateRequest

+ +

+ + +

+
{
+  "description": "My first Group",
+  "name": "Group 01",
+  "workspace": "60b9d1c8e1f1d5f5f5b4f8e1"
+}
+
+

GroupCreateRequest

+

Properties

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
namestringfalsenonenone
workspacestringtruenonenone
descriptionstringfalsenonenone
+

GroupList

+ +

+ + +

+
{
+  "groups": [
+    {
+      "id": "5eb7cf5a86d9755df3a6c593",
+      "name": "string",
+      "description": "string"
+    }
+  ]
+}
+
+

GroupList

+

Properties

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
groupsanytruenonenone
+

anyOf

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
» anonymous[GroupShort]falsenonenone
+

or

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
» anonymous[Group]falsenonenone
+

GroupShort

+ +

+ + +

+
{
+  "id": "5eb7cf5a86d9755df3a6c593",
+  "name": "string",
+  "description": "string"
+}
+
+

GroupShort

+

Properties

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
idstringtruenonenone
namestringtruenonenone
descriptionstringtruenonenone
+

GroupUpdateRequest

+ +

+ + +

+
{
+  "Description": "Updated description"
+}
+
+

GroupUpdateRequest

+

Properties

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
nameanyfalsenonenone
+

anyOf

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
» anonymousstringfalsenonenone
+

or

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
» anonymousnullfalsenonenone
+

continued

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
descriptionanyfalsenonenone
+

anyOf

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
» anonymousstringfalsenonenone
+

or

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
» anonymousnullfalsenonenone
+

HTTPValidationError

+ +

+ + +

+
{
+  "detail": [
+    {
+      "loc": [
+        "string"
+      ],
+      "msg": "string",
+      "type": "string"
+    }
+  ]
+}
+
+

HTTPValidationError

+

Properties

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
detail[ValidationError]falsenonenone
+

LoginResponse

+ +

+ + +

+
{
+  "access_token": "string",
+  "token_type": "Bearer",
+  "scope": "string",
+  "client_id": "string",
+  "expires_in": 3600,
+  "refresh_token": "string"
+}
+
+

LoginResponse

+

Properties

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
access_tokenstringtruenonenone
token_typestringfalsenonenone
scopeanyfalsenonenone
+

anyOf

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
» anonymousstringfalsenonenone
+

or

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
» anonymousnullfalsenonenone
+

continued

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
client_idanyfalsenonenone
+

anyOf

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
» anonymousstringfalsenonenone
+

or

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
» anonymousnullfalsenonenone
+

continued

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
expires_inintegerfalsenonenone
refresh_tokenstringtruenonenone
+

Member

+ +

+ + +

+
{
+  "email": "user@example.com",
+  "first_name": "John",
+  "id": "1a2b3c4d5e6f7g8h9i0j",
+  "last_name": "Doe"
+}
+
+

Member

+

Properties

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
idstringtruenonenone
emailanyfalsenonenone
+

anyOf

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
» anonymousstring(email)falsenonenone
+

or

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
» anonymousnullfalsenonenone
+

continued

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
first_nameanyfalsenonenone
+

anyOf

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
» anonymousstringfalsenonenone
+

or

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
» anonymousnullfalsenonenone
+

continued

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
last_nameanyfalsenonenone
+

anyOf

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
» anonymousstringfalsenonenone
+

or

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
» anonymousnullfalsenonenone
+

continued

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
nameanyfalsenonenone
+

anyOf

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
» anonymousstringfalsenonenone
+

or

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
» anonymousnullfalsenonenone
+

continued

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
descriptionanyfalsenonenone
+

anyOf

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
» anonymousstringfalsenonenone
+

or

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
» anonymousnullfalsenonenone
+

MemberList

+ +

+ + +

+
{
+  "members": [
+    {
+      "email": "jdoe@example.com",
+      "first_name": "John",
+      "last_name": "Doe",
+      "role": "admin"
+    },
+    {
+      "email": "jsmith@example.com",
+      "first_name": "Jack",
+      "last_name": "Smith",
+      "role": "user"
+    }
+  ]
+}
+
+

MemberList

+

Properties

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
members[Member]truenonenone
+

PermissionList

+ +

+ + +

+
{
+  "permissions": [
+    "get_workspaces",
+    "create_workspace",
+    "get_workspace",
+    "update_workspace",
+    "delete_workspace",
+    "get_workspace_members",
+    "add_workspace_members",
+    "remove_workspace_member",
+    "get_groups",
+    "create_group",
+    "get_workspace_policies",
+    "get_workspace_policy",
+    "set_workspace_policy",
+    "get_workspace_permissions"
+  ]
+}
+
+

PermissionList

+

Properties

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
permissions[string]truenonenone
+

PolicyInput

+ +

+ + +

+
{
+  "permissions": [
+    "get_workspace_info",
+    "list_members"
+  ]
+}
+
+

PolicyInput

+

Properties

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
policy_idanyfalsenonenone
+

anyOf

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
» anonymousstringfalsenonenone
+

or

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
» anonymousnullfalsenonenone
+

continued

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
account_idanyfalsenonenone
+

anyOf

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
» anonymousstringfalsenonenone
+

or

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
» anonymousnullfalsenonenone
+

continued

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
group_idanyfalsenonenone
+

anyOf

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
» anonymousstringfalsenonenone
+

or

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
» anonymousnullfalsenonenone
+

continued

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
permissions[string]truenonenone
+

PolicyList

+ +

+ + +

+
{
+  "policies": [
+    {
+      "permissions": [
+        "get_workspace",
+        "get_groups"
+      ],
+      "policy_holder": {
+        "email": "email@example.com",
+        "first_name": "Name",
+        "id": "1a2b3c4d5e6f7g8h9i0j",
+        "last_name": "Surname"
+      }
+    },
+    {
+      "permissions": [
+        "get_workspace",
+        "get_groups"
+      ],
+      "policy_holder": {
+        "email": "email@example.com",
+        "first_name": "Name",
+        "id": "1a2b3c4d5e6f7g8h9i0j",
+        "last_name": "Surname"
+      }
+    }
+  ]
+}
+
+

PolicyList

+

Properties

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
policies[PolicyShort]truenonenone
+

PolicyOutput

+ +

+ + +

+
{
+  "permissions": [
+    "get_workspaces",
+    "create_workspace",
+    "get_workspace",
+    "update_workspace",
+    "delete_workspace",
+    "get_workspace_members",
+    "add_workspace_members",
+    "remove_workspace_member",
+    "get_groups",
+    "create_group",
+    "get_all_workspace_policies",
+    "get_workspace_policy",
+    "set_workspace_policy"
+  ],
+  "policy_holder": {
+    "email": "email@example.com",
+    "first_name": "Name",
+    "id": "1a2b3c4d5e6f7g8h9i0j",
+    "last_name": "Surname"
+  }
+}
+
+

PolicyOutput

+

Properties

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
permissions[string]truenonenone
policy_holderanyfalsenonenone
+

PolicyShort

+ +

+ + +

+
{
+  "id": "5eb7cf5a86d9755df3a6c593",
+  "policy_holder_type": "account",
+  "policy_holder": null,
+  "permissions": {}
+}
+
+

PolicyShort

+

Properties

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
idstringtruenonenone
policy_holder_typestringtruenonenone
policy_holderanyfalsenonenone
permissionsanyfalsenonenone
+

anyOf

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
» anonymousanyfalsenonenone
+

or

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
» anonymousnullfalsenonenone
+

Enumerated Values

+ + + + + + + + + + + + + + + + + +
PropertyValue
policy_holder_typeaccount
policy_holder_typegroup
+

PollList

+ +

+ + +

+
{
+  "polls": [
+    {
+      "description": "This is an example poll",
+      "id": "1a2b3c4d5e6f7g8h9i0j",
+      "name": "Poll 01",
+      "published": true
+    },
+    {
+      "description": "This is an example poll",
+      "id": "1a2b3c4d5e6f7g8h9i0j",
+      "name": "Poll 02",
+      "published": true
+    }
+  ]
+}
+
+

PollList

+

Properties

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
polls[PollShort]truenonenone
+

PollResponse

+ +

+ + +

+
{
+  "description": "This is an example poll",
+  "id": "1a2b3c4d5e6f7g8h9i0j",
+  "name": "Poll 01",
+  "published": true
+}
+
+

PollResponse

+

Properties

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
idanyfalsenonenone
+

anyOf

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
» anonymousstringfalsenonenone
+

or

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
» anonymousnullfalsenonenone
+

continued

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
workspaceanyfalsenonenone
+

anyOf

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
» anonymousanyfalsenonenone
+

or

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
» anonymousnullfalsenonenone
+

continued

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
namestringtruenonenone
descriptionstringtruenonenone
publicbooleantruenonenone
publishedbooleantruenonenone
questionsanyfalsenonenone
+

anyOf

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
» anonymous[Question]falsenonenone
+

or

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
» anonymousnullfalsenonenone
+

continued

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
policiesanyfalsenonenone
+

anyOf

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
» anonymous[any]falsenonenone
+

or

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
» anonymousnullfalsenonenone
+

PollShort

+ +

+ + +

+
{
+  "poll": {
+    "description": "This is an example poll",
+    "id": "1a2b3c4d5e6f7g8h9i0j",
+    "name": "Poll 01",
+    "published": true
+  }
+}
+
+

PollShort

+

Properties

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
idstringtruenonenone
namestringtruenonenone
descriptionstringtruenonenone
publicbooleantruenonenone
publishedbooleantruenonenone
+

Question

+ +

+ + +

+
{
+  "id": 0,
+  "question": "string",
+  "question_type": "string",
+  "options": [
+    "string"
+  ],
+  "correct_answer": [
+    0
+  ]
+}
+
+

Question

+

Properties

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
idintegertruenonenone
questionstringtruenonenone
question_typestringtruenonenone
options[string]truenonenone
correct_answer[integer]truenonenone
+

QuestionList

+ +

+ + +

+
{
+  "questions": [
+    {
+      "id": 0,
+      "question": "string",
+      "question_type": "string",
+      "options": [
+        "string"
+      ],
+      "correct_answer": [
+        0
+      ]
+    }
+  ]
+}
+
+

QuestionList

+

Properties

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
questions[Question]truenonenone
+

UpdateAccount

+ +

+ + +

+
{
+  "email": "user@example.com",
+  "first_name": "John",
+  "last_name": "Smith",
+  "password": "pass1234"
+}
+
+

UpdateAccount

+

Properties

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
passwordanyfalsenonenone
+

anyOf

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
» anonymousstringfalsenonenone
+

or

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
» anonymousnullfalsenonenone
+

continued

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
emailstring(email)truenonenone
is_activeanyfalsenonenone
+

anyOf

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
» anonymousbooleanfalsenonenone
+

or

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
» anonymousnullfalsenonenone
+

continued

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
is_superuseranyfalsenonenone
+

anyOf

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
» anonymousbooleanfalsenonenone
+

or

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
» anonymousnullfalsenonenone
+

continued

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
is_verifiedanyfalsenonenone
+

anyOf

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
» anonymousbooleanfalsenonenone
+

or

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
» anonymousnullfalsenonenone
+

continued

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
first_namestringfalsenonenone
last_namestringfalsenonenone
+

UpdatePollRequest

+ +

+ + +

+
{
+  "description": "This is an example poll",
+  "name": "Poll 01",
+  "published": true
+}
+
+

UpdatePollRequest

+

Properties

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
nameanyfalsenonenone
+

anyOf

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
» anonymousstringfalsenonenone
+

or

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
» anonymousnullfalsenonenone
+

continued

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
descriptionanyfalsenonenone
+

anyOf

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
» anonymousstringfalsenonenone
+

or

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
» anonymousnullfalsenonenone
+

continued

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
publicanyfalsenonenone
+

anyOf

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
» anonymousbooleanfalsenonenone
+

or

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
» anonymousnullfalsenonenone
+

continued

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
publishedanyfalsenonenone
+

anyOf

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
» anonymousbooleanfalsenonenone
+

or

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
» anonymousnullfalsenonenone
+

continued

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
questionsanyfalsenonenone
+

anyOf

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
» anonymous[Question]falsenonenone
+

or

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
» anonymousnullfalsenonenone
+

ValidationError

+ +

+ + +

+
{
+  "loc": [
+    "string"
+  ],
+  "msg": "string",
+  "type": "string"
+}
+
+

ValidationError

+

Properties

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
loc[anyOf]truenonenone
+

anyOf

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
» anonymousstringfalsenonenone
+

or

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
» anonymousintegerfalsenonenone
+

continued

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
msgstringtruenonenone
typestringtruenonenone
+

Workspace

+ +

+ + +

+
{
+  "description": "This is an example workspace",
+  "id": "1a2b3c4d5e6f7g8h9i0j",
+  "name": "Workspace 01"
+}
+
+

Workspace

+

Properties

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
idanyfalsenonenone
+

anyOf

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
» anonymousstringfalsenonenone
+

or

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
» anonymousnullfalsenonenone
+

continued

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
nameanyfalsenonenone
+

anyOf

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
» anonymousstringfalsenonenone
+

or

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
» anonymousnullfalsenonenone
+

continued

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
descriptionanyfalsenonenone
+

anyOf

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
» anonymousstringfalsenonenone
+

or

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
» anonymousnullfalsenonenone
+

continued

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
membersanyfalsenonenone
+

anyOf

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
» anonymous[any]falsenonenone
+

or

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
» anonymousnullfalsenonenone
+

continued

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
groupsanyfalsenonenone
+

anyOf

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
» anonymous[any]falsenonenone
+

or

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
» anonymousnullfalsenonenone
+

continued

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
policiesanyfalsenonenone
+

anyOf

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
» anonymous[any]falsenonenone
+

or

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
» anonymousnullfalsenonenone
+

continued

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
pollsanyfalsenonenone
+

anyOf

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
» anonymous[any]falsenonenone
+

or

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
» anonymousnullfalsenonenone
+

WorkspaceCreateInput

+ +

+ + +

+
{
+  "description": "This is an example workspace",
+  "name": "Workspace 01"
+}
+
+

WorkspaceCreateInput

+

Properties

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
namestringtruenonenone
descriptionstringtruenonenone
+

WorkspaceCreateOutput

+ +

+ + +

+
{
+  "description": "This is an example workspace",
+  "name": "Workspace 01"
+}
+
+

WorkspaceCreateOutput

+

Properties

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
idstringtruenonenone
namestringtruenonenone
descriptionstringtruenonenone
+

WorkspaceList

+ +

+ + +

+
{
+  "workspaces": [
+    {
+      "description": "This is an example workspace",
+      "name": "Workspace 01",
+      "owner": "true"
+    },
+    {
+      "description": "This is another example workspace",
+      "name": "Workspace 02",
+      "owner": "false"
+    }
+  ]
+}
+
+

WorkspaceList

+

Properties

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
workspacesanytruenonenone
+

anyOf

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
» anonymous[WorkspaceShort]falsenonenone
+

or

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
» anonymous[Workspace]falsenonenone
+

WorkspaceShort

+ +

+ + +

+
{
+  "id": "5eb7cf5a86d9755df3a6c593",
+  "name": "string",
+  "description": "string"
+}
+
+

WorkspaceShort

+

Properties

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
idstringtruenonenone
namestringtruenonenone
descriptionstringtruenonenone
+

WorkspaceUpdateRequest

+ +

+ + +

+
{
+  "description": "This is an example workspace",
+  "name": "Workspace 01"
+}
+
+

WorkspaceUpdateRequest

+

Properties

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
nameanyfalsenonenone
+

anyOf

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
» anonymousstringfalsenonenone
+

or

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
» anonymousnullfalsenonenone
+

continued

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
descriptionanyfalsenonenone
+

anyOf

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
» anonymousstringfalsenonenone
+

or

+ + + + + + + + + + + + + + + + + + + +
NameTypeRequiredRestrictionsDescription
» anonymousnullfalsenonenone
+ + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/api-docs/usage/Authentication/index.html b/api-docs/usage/Authentication/index.html new file mode 100644 index 0000000..492d0c0 --- /dev/null +++ b/api-docs/usage/Authentication/index.html @@ -0,0 +1,1509 @@ + + + + + + + + + + + + + + + + + + + + + + + Authentication - University Polling + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+ +
+
+ + + +
+
+ + + + + + + +

Authentication

+

API authentication is based on OAuth 2.0 protocol. The API uses JWT (JSON Web Token) or Cookies for authentication.

+

Authentication is required for all API requests. You can authenticate by sending an access token in the Authorization header. To get an access token, user need to log in with their username and password.

+

Note: Currently, cookies support has been disabled. Only JWT is supported.

+

To learn more about OAuth 2.0, visit OAuth 2.0.

+

To learn more about JWT, visit JWT.

+

Login request

+

To log in, send a POST request to /auth/jwt/login with application/x-www-form-urlencoded content type. The request body must contain the following parameters:

+

Request body:

+
    +
  • grant_type - Must be password
  • +
  • username - Username of the user
  • +
  • password - Password of the user
  • +
  • scope - Optional - Scope of the token (currently not used)
  • +
  • client_id - Optional - Client ID (currently we use Account ID, which is provided during registration)
  • +
  • client_secret - Optional - Client Secret (currently not used)
  • +
+

Request Example:

+
POST /auth/jwt/login HTTP/1.1
+Host: <api-url>:<port>
+Content-Type: application/x-www-form-urlencoded
+Accept: application/json
+Content-Length: 120
+
+grant_type=password&username=******&password=******
+
+

Response:

+

The login request returns a JSON object containing the following parameters:

+
    +
  • access_token - Access token
  • +
  • refresh_token - Refresh token
  • +
  • token_type - Type of the token (bearer)
  • +
  • expires_in - Time in seconds for how long the token is valid (1 hour)
  • +
+

Response example:

+
{
+  "access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoiOTIyMWZmYzktNjQwZi00MzcyLTg2ZDMtY2U2NDJjYmE1NjAzIiwiYXVkIjoiZmFzdGFwaS11c2VyczphdXRoIiwiZXhwIjoxNTcxNTA0MTkzfQ.M10bjOe45I5Ncu_uXvOmVV8QxnL-nZfcH96U90JaocI",
+  "refresh_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoiOTIyMWZmYzktNjQwZi00MzcyLTg2ZDMtY2U2NDJjYmE1NjAzIiwiYXVkIjoiZmFzdGFwaS11c2VyczphdXRoIiwiZXhwIjoxNTcxNTA0MTkzfQ.M10bjOe45I5Ncu_uXvOmVV8QxnL-nZfcH96U90JaocI",
+  "token_type": "bearer",
+  "expires_in": 3600
+}
+
+

Client ID and Client Secret

+

The purpose of Client ID and Client Secret is to allow users to create multiple applications and use the same account to log in to all of them. For example, a user can create a mobile app and a web app. Both apps will use the same account to log in, but they will have different Client IDs and Client Secrets.

+

Another use case is to request a refresh token. The refresh token is used to get a new access token when the current one expires. The refresh token is only valid for a limited time and can only be used once. To get a refresh token, the user must provide Client ID and Client Secret.

+

Note: At the moment, the API does not use/process Client ID and Client Secret. For development purpose, we use Account ID as Client ID to refresh token. This way developers do not need to re-login, when the access token expires.

+

To learn more about Client ID and Client Secret, visit OAuth 8.2: Client ID and Client Secret.

+

Refresh token request

+

Simple refresh token request

+

Note: This request is currently in development, and will likely change in the future.

+

When the access token expires, the user can request a new access token by sending a POST request to /auth/jwt/refresh with the refresh tokens in the request header. The response will contain a new access token and a new refresh token.

+

Request header parameters:

+
    +
  • refresh-token
  • +
+

Request example:

+
POST /auth/jwt/refresh HTTP/1.1
+Host: <api-url>:<port>
+refresh-token: <string>
+Accept: application/json
+
+

Postman refresh token request

+

For development purposes, when using Postman, you should use /auth/jwt/postman-refresh endpoint to refresh the token. This endpoint will return a new access token and a new refresh token.

+

Postman Authentication

+

Authentication with cookies

+

Note: This feature is currently disabled.

+ + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/api-docs/usage/Configuration/index.html b/api-docs/usage/Configuration/index.html new file mode 100644 index 0000000..b8d0ef9 --- /dev/null +++ b/api-docs/usage/Configuration/index.html @@ -0,0 +1,1435 @@ + + + + + + + + + + + + + + + + + + + + + + + Configuration - University Polling + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

Configuration

+

For API configuration and settings we use Pydantic Settings module.

+

The configuration is loaded from environment variable and can be saved in .env file for persistance.

+

Interactive Configuration Wizard

+

For the convenience you can run interactive configuration wizard by running:

+
$ unipoll-api setup
+
+

Configuration Variables

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
VariablesDescriptionDefault
ADMIN_EMAILEmail of the administrator of the applicationadmin@example.com
MONGODB_URLURL of the MongoDB database used by the applicationmongodb://localhost:27017
SECRET_KEYSecrete key used for Authentication and Authorizationsecret
ORIGINSList of allowed origins for CORS*
HOSTIP address to bind to0.0.0.0
PORTPort to bind to9000
RELOADEnable auto-reloadTrue
+

Additional Info

+

Host - IP address to bind to. Only IPv4 is supported for now.

+

Origins - List of allowed origins for CORS. The connections from other origins will be rejected. You can specify multiple origins by separating them with comma. For example: http://localhost:3000,http://localhost:3001 or use * to allow all origins.

+

Reload - Enable auto-reload. This is useful for development. For production you should disable auto-reload. The reload will restart the server when any of the source files are changed.

+ + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/api-docs/usage/Deployment/index.html b/api-docs/usage/Deployment/index.html new file mode 100644 index 0000000..aecef06 --- /dev/null +++ b/api-docs/usage/Deployment/index.html @@ -0,0 +1,1591 @@ + + + + + + + + + + + + + + + + + + + + + + + Deployment of the API - University Polling + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

Deployment of the API

+

The API is a Python package that can be installed on a Linux system. You can install the package from PyPI, from source, or run it in a Docker container.

+

Prerequisites

+

The API uses MongoDB as a database. You can either use a local instance of MongoDB or use a cloud service such as MongoDB Atlas. Specify the connection string in the MONGODB_URL environment variable.

+

Installing the API from PyPI

+
pip install unipoll-api
+
+

Running the API

+
unipoll-api run
+
+

You can then create a systemd service to run the application as daemon.

+

Running in Docker

+

Make sure you have installed latest Docker on your system.

+

Running in docker +

docker run unipoll/api -e MONGODB_URI=<your connection string>
+

+

Docker Compose

+

You can also use docker-compose file which will run the MongoDB database in a separate container along side the API container.

+
services:
+  mongodb:
+    image: 'mongo:latest'
+    ports:
+      - '27017:27017'
+    environment:
+      MONGO_INITDB_ROOT_USERNAME: root
+      MONGO_INITDB_ROOT_PASSWORD: changeme
+
+  api:
+    image: 'unipoll/api:latest'
+    ports:
+      - '80:8000'
+    environment:
+      MONGODB_URL: mongodb://root:changeme@mongodb:27017
+      PORT: 8000
+
+

Run the compose file with +

docker compose up -d
+

+

Kubernetes deployment

+

You can deploy the API to Kubernetes cluster using the following manifests:

+
+
+
+
apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: unipoll-api
+  namespace: unipoll
+  labels:
+    app: unipoll-api
+spec:
+  replicas: 2
+  selector:
+    matchLabels:
+      app: unipoll-api
+  template:
+    metadata:
+      labels:
+        app: unipoll-api
+    spec:
+      containers:
+      - name: unipoll-api
+        image: unipoll/api:latest
+        args: ["--host=0.0.0.0"]
+        ports:
+        - containerPort: 80
+        env:
+        - name: MONGODB_URL
+          value: "mongodb://root:9nLkOk853z@10.0.2.162:27017"
+
+
+
+
apiVersion: v1
+kind: Service
+metadata:
+  name: unipoll-api
+  namespace: unipoll
+spec:
+  selector:
+    app: unipoll-api
+  ports:
+  - port: 80
+    targetPort: 9000
+    protocol: TCP
+    name: http
+
+
+
+
apiVersion: networking.k8s.io/v1
+kind: Ingress
+metadata:
+  name: unipoll-api
+  labels:
+    name: unipoll-api
+spec:
+  rules:
+  - host: unipoll-api.1cl.cc
+    http:
+      paths:
+      - pathType: Prefix
+        path: "/"
+        backend:
+          service:
+            name: unipoll-api
+            port:
+              number: 80
+
+
+
+
+

Instal the package from source

+

Get the latest version of the API from the releases page

+

Make sure you have the following installed on your system:

+
    +
  • Python 3.11
  • +
  • pip
  • +
+

Unpack the archive with +

$ tar xvfz unipoll-api-<version>.tar.gz
+

+

Optionally, create a virtual environment. Make sure you have installed venv package. You can create a virtual environment using the following command: +

$ pip install venv
+$ python -m venv venv
+$ source ven/bin/activate
+

+

Run the following command in the root directory of the project:

+
$ pip install .
+
+

This will install the package and all its dependencies on your system. +The you can run the API as a service using systemd.

+ + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/api-docs/usage/OpenAPI/index.html b/api-docs/usage/OpenAPI/index.html new file mode 100644 index 0000000..289f105 --- /dev/null +++ b/api-docs/usage/OpenAPI/index.html @@ -0,0 +1,1280 @@ + + + + + + + + + + + + + + + + + + + + + + + OpenAPI - University Polling + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

OpenAPI

+

As our API is built using FastAPI, we can use OpenAPI to document our API. OpenAPI is a specification for describing RESTful APIs. It allows us to describe the API in a human-readable format and generate documentation and client libraries automatically.

+

Another great advantage of using OpenAPI is abundance of tools that support it. For example, we can use Swagger UI to generate a beautiful documentation for our API. We can also use Postman to generate client libraries for our API.

+

One particular advantage that is not necessarily obvious is that you can generate clients (sometimes called SDKs ) for your API, for many different programming languages.

+

There are many tools to generate clients from OpenAPI.

+

A common tool is OpenAPI Generator

+

If you are building a frontend, a very interesting alternative is openapi-typescript-codegen

+ + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/api-docs/usage/Overview/index.html b/api-docs/usage/Overview/index.html new file mode 100644 index 0000000..58d7243 --- /dev/null +++ b/api-docs/usage/Overview/index.html @@ -0,0 +1,1550 @@ + + + + + + + + + + + + + + + + + + + + + + + API Overview - University Polling + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

API Overview

+

This section will go over main components of the API and how to use them.

+
flowchart LR
+    Accs(Accounts) -----------> A1(John)
+
+    Ws(Workspaces) --> W1(Workspace)
+
+    W1 --> W1Polls(Polls)
+    W1 --> W1Gs(Groups) 
+    W1 --> W1Ps(Policies)
+    W1 --> W1Ms(Workspace \n Members)
+
+
+    W1Gs -----> G1(Group A)
+    G1 --> G1Ps(Policies)
+    G1Ps ---> G1P1(John Group Policy)
+    G1 --> G1Ms(Group Members)
+    G1Ms ----> W1M1(Member John)
+    G1P1 --> W1M1
+
+    W1Ps --> W1P2(Group A Policy)
+    W1P2 ----> G1
+    W1M1 --> A1
+
+    W1Ps --> W1P1(John Workspace Policy)
+
+    W1Ms ---------> W1M1(Member John)
+    W1P1 --------> W1M1
+
+    W1Polls --> W1Poll1(Poll)
+    W1Poll1 --> Poll1Ps(Policies)
+    Poll1Ps --> Poll1P1(Group A Policy)
+    Poll1P1 --> G1
+

Accounts

+

Accounts represent users of the API. They are used to authenticate and authorize users. +When user registers, an account is created for them.

+

Class Definition:

+
    +
  • id - unique identifier of the account
  • +
  • email - email address of the account
  • +
  • password - password of the account (stored hashed)
  • +
  • First Name - first name of the account
  • +
  • Last Name - last name of the account
  • +
+

Workspaces

+

The API is organized around workspaces. Each workspace has its own set of groups, policies, members and polls. +You can think of workspace as a separate organization, or a class, or simply an isolated environment. Every user can create a workspace and invite other users to it.

+
flowchart LR
+    Accs(Accounts) --------> A1(John)
+
+    Ws(Workspaces) --> W1(Workspace)
+
+    W1 ----> W1Polls(Polls)
+    W1 --> W1Gs(Groups) 
+    W1 ----> W1Ps(Policies)
+    W1 --> W1Ms(Members)
+
+
+    W1Gs -----> G1(Group)
+
+    W1Ps --> W1P2(Group Policy)
+    W1P2 ----> G1
+
+    W1Ps --> W1P1(John Policy)
+    W1P1 -.-> W1M1
+
+    W1Ms ---> W1M1(Member John)
+    W1M1 --> A1
+
+    W1Polls --> W1Poll1(Poll)
+    W1Poll1 --> Poll1Ps(Policies)
+    Poll1Ps --> Poll1P1(Group Policy)
+    Poll1P1 -.-> G1
+

Class Definition:

+
    +
  • id - Unique identifier of the workspace document
  • +
  • name - Name of the workspace, must be unique
  • +
  • description - Description of the workspace
  • +
  • members - List of members of the workspace
  • +
  • groups - List of groups in the workspace
  • +
  • policies - List of policies in the workspace
  • +
  • polls - List of polls in the workspace
  • +
+

Members

+

When a user is invited to a workspace, they become a member of that workspace. Members can be assigned to groups. Each member has a unique policy in the workspace which defines their permissions in the workspace.

+

Similarly, groups also have members and policies. To become a member of a group, a user must first be a member of the workspace. Each member of the group has a unique Group policy which defines their permissions in the group.

+

Member class is used to link accounts to resources.

+

Class Definition:

+
    +
  • id - Unique identifier of the member document
  • +
  • account - Account of the member
  • +
  • workspace - Workspace the member belongs to
  • +
  • groups - List of groups the member belongs to
  • +
  • policies - List of policies of the member in the workspace/groups/polls
  • +
+

Groups

+

Groups allow you to organize members of the workspace. Each group has its own policy in the workspace which defines permissions of all members of that group.

+
flowchart LR
+    Accs(Accounts) -------> A1(John)
+
+    G1(Group)
+    G1 ----> G1Ps(Policies)
+    G1 --> G1Ms(Members)
+    G1Ms ---> W1M1(Member John)
+    G1Ps --> G1P1(John Policy)
+    G1P1 --> W1M1
+
+    W1Ms(Workspace Memmber)
+    W1Ms ------> W1M1(Member John)
+    W1M1 --> A1
+

Class Definition:

+
    +
  • id - Unique identifier of the group
  • +
  • name - Name of the group, must be unique
  • +
  • description - Description of the group
  • +
  • members - List of members of the group
  • +
  • policies - List of policies in the group
  • +
  • workspace - Workspace the group belongs to
  • +
+

Policies

+

Policies define permissions of members and groups. Each member or group has a unique policy in the workspace. Inside group, each member has a unique Group policy.

+

Class Definition:

+
    +
  • id - Unique identifier of the policy
  • +
  • parent_resource - Resource the policy belongs to (workspace, group, poll)
  • +
  • policy_holder_type - Type of the policy holder (Internal usage)
  • +
  • policy_holder - Policy holder (Account/Group)
  • +
  • permissions - Integer representation of permissions
  • +
+

Polls

+

Polls are used to collect votes from members of the workspace. Each poll has its own set of questions and policies. Policies define permissions of members and groups in the workspace, which actions they can perform in the poll. The polls can be public or private. Public polls can be accessed by anyone, while private polls can only be accessed by members with appropriate permissions.

+ + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/api-docs/usage/Permissions/index.html b/api-docs/usage/Permissions/index.html new file mode 100644 index 0000000..9448576 --- /dev/null +++ b/api-docs/usage/Permissions/index.html @@ -0,0 +1,1440 @@ + + + + + + + + + + + + + + + + + + + + + + + Permission System - University Polling + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

Permission System

+

Introduction

+

Permissions define what actions can be performed on a resource. Each permission has a unique name and represents a specific action in the related resource. Each resource contains a list of policies which define permissions of members and groups. Upon every action, the API checks member policies and policies of group which the user is a member of. It will check the policies inside the resource as well as in check the policies of the parent resource in case of Group and Poll resources. Then API will calculate the maximum permission of the user based on all found policies and perform the action if the user has the required permission. Otherwise, the API will return an error.

+

Binary System

+

Inside the policy, permissions are represented as integers. An integer can be converted to a binary number, in which each bit represents a specific permission. For example, if the permission is 4, the binary number then is 0b1010, it means that the resource has permissions 0b1000 and 0b0010. This system allows for efficient use of space as well as fast calculation of permissions. Using bitwise operators the system can quickly check if a user has a required permission.

+

Permission Types

+

There are currently 3 types/classes of permissions: Workspace Permissions, Group Permissions, and Poll Permissions.

+
+
+
+

get_workspace - Get workspace information
+update_workspace - Update workspace information (name, description)
+delete_workspace - Delete workspace
+get_members - Get list of members in the workspace
+add_members - Add members to the workspace
+remove_members - Remove members from the workspace
+get_groups - Get list of groups in the workspace
+add_groups - Add groups to the workspace
+update_groups - Update groups in the workspace
+delete_groups - Delete groups from the workspace
+get_policies - Get list of policies in the workspace
+add_policies - Add policies to the workspace
+update_policies - Update policies in the workspace
+delete_policies - Delete policies from the workspace
+get_polls - Get list of polls in the workspace
+create_polls - Create polls in the workspace
+delete_polls - Delete polls from the workspace

+
+
+

get_group - Get group information
+update_group - Get group information
+delete_group - Delete group
+get_members - Get list of members in the group
+add_members - Add members to the group
+remove_members - Remove members from the group
+get_policies - Get list of policies in the group
+add_policies - Add policies to the group
+update_policies - Update policies in the group (set permissions)
+delete_policies - Delete policies from the group

+
+
+

get_poll - Get poll information
+get_questions - Get questions in the poll
+update_poll - Update poll (name, description, questions)
+delete_poll - Delete poll
+get_policies - Get list of policies in the poll
+add_policies - Add policies to the poll
+update_policies - Update policies in the poll (set permissions)
+delete_policies - Delete policies from the poll

+
+
+
+

Permission Requests and Responses

+

The user can request the list of all available permissions for a specific type of resource.

+

For example, to get list of available permissions for Workspace, the client can send a GET request to https://<api-url>/workspaces/permissions

+

Note: The user must be authenticated to make this request.

+

To update policies, the Request body accepts permissions as a list of strings. The API will convert the list of strings to the appropriate integer and store it in the database. When the API returns a list of policies, it will convert the digit to a list of strings.

+ + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/api-docs/usage/Quick Start/index.html b/api-docs/usage/Quick Start/index.html new file mode 100644 index 0000000..a48adc9 --- /dev/null +++ b/api-docs/usage/Quick Start/index.html @@ -0,0 +1,1433 @@ + + + + + + + + + + + + + + + + + + + + + + + Quick Start - University Polling + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

Quick Start

+

Installation

+

You can install the API using pip:

+
+ pip install unipoll-api + + Done!
+
+ +

Check Deployment section for more information.

+

Launching the API

+

Use run command to launch the API server:

+

You can specify server address and port using --host and --port options:

+
+ unipoll-api run --port 9000 + INFO: University Polling API v0.11.3 + INFO: Started server process [1842018] + INFO: Waiting for application startup. + INFO: Application startup complete. + INFO: Uvicorn running on http://0.0.0.0:9000 (Press CTRL+C to quit) +
+ +

For more help use -h or --help option:

+
$ unipoll-api -h
+
+
$ unipoll-api run -h
+
+

Learn more about the available options in the Configuration section.

+ + +

Access API Reference

+

Now you can connect your client application to the API server at http://localhost:9000.

+

Once the server is running you can access the API reference at http://localhost:9000/docs or http://localhost:9000/redoc.

+ + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/api-docs/usage/index.html b/api-docs/usage/index.html new file mode 100644 index 0000000..43e3f02 --- /dev/null +++ b/api-docs/usage/index.html @@ -0,0 +1,1265 @@ + + + + + + + + + + + + + + + + + + + + + + + API Documentation - University Polling + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

API Documentation

+

This is the API documentation for the {{ cookiecutter.project_slug }} project.

+ + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/assets/favicon.ico b/assets/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..71e25109068cb2527a5b260eab25a2f728da1709 GIT binary patch literal 4286 zcmeH}J#O1T5QUd;0F`1DAV7c+NRxDG)5JW2j>2>n5P))#z@@6x0@9=lZy@Fb)(xU2 zwKtstBxb%RaD~;Hr2gp6V?535%y8b@k!;zRh@T`edNto-W1bsh-T+c21KekQk1fhz$sumWwiq>uqV0sWX}fjKzFEX~=u3Ya18gGC6ZUXl4=k(~F7HF2V z%)t)7W|AA#b=<~EUX_#H)bTn`ZXbV4PXT0_vEjsLU-^UZSD&LQ66=d4-k zxdVP*%vo9ruya?Pfzvyy&m;U2v{^wR23vk&H$%_N!@KBAehjv|sLvLEis`wpVDtIM zFMw~-lY~0RNw;<(9p~C720U{d#2L`;ok?Tn>b@sG27a%5<`92N)5xFaV)6-C0N?iQ z!tdP|=Z>q(GoGc)JR9QMau)O=X#!i9;T z37kk-upj^(fsR36MHs_+1RCI)NNu9}lD0S{B^g8PN?Ww(5|~L#Ng*g{WsqleV}|#l zz8@ri&cTzw_h33bHI+12+kK6WN$h#n5cD8OQt`5kw6p~9H3()bUQ8OS4Q4HTQ=1Ol z_JAocz`fLbT2^{`8n~UAo=#AUOf=SOq4pYkt;XbC&f#7lb$*7=$na!mWCQ`dBQsO0 zLFBSPj*N?#u5&pf2t4XjEGH|=pPQ8xh7tpx;US5Cx_Ju;!O`ya-yF`)b%TEt5>eP1ZX~}sjjA%FJF?h7cX8=b!DZl<6%Cv z*G0uvvU+vmnpLZ2paivG-(cd*y3$hCIcsZcYOGh{$&)A6*XX&kXZd3G8m)G$Zz-LV z^GF3VAW^Mdv!)4OM8EgqRiz~*Cji;uzl2uC9^=8I84vNp;ltJ|q-*uQwGp2ma6cY7 z;`%`!9UXO@fr&Ebapfs34OmS9^u6$)bJxrucutf>`dKPKT%%*d3XlFVKunp9 zasduxjrjs>f8V=D|J=XNZp;_Zy^WgQ$9WDjgY=z@stwiEBm9u5*|34&1Na8BMjjgf3+SHcr`5~>oz1Y?SW^=K z^bTyO6>Gar#P_W2gEMwq)ot3; zREHn~U&Dp0l6YT0&k-wLwYjb?5zGK`W6S2v+K>AM(95m2C20L|3m~rN8dprPr@t)5lsk9Hu*W z?pS990s;Ez=+Rj{x7p``4>+c0G5^pYnB1^!TL=(?HLHZ+HicG{~4F1d^5Awl_2!1jICM-!9eoLhbbT^;yHcefyTAaqRcY zmuctDopPT!%k+}x%lZRKnzykr2}}XfG_ne?nRQO~?%hkzo;@RN{P6o`&mMUWBYMTe z6i8ChtjX&gXl`nvrU>jah)2iNM%JdjqoaeaU%yVn!^70x-flljp6Q5tK}5}&X8&&G zX3fpb3E(!rH=zVI_9Gjl45w@{(ITqngWFe7@9{mX;tO25Z_8 zQHEpI+FkTU#4xu>RkN>b3Tnc3UpWzPXWm#o55GKF09j^Mh~)K7{QqbO_~(@CVq! zS<8954|P8mXN2MRs86xZ&Q4EfM@JB94b=(YGuk)s&^jiSF=t3*oNK3`rD{H`yQ?d; ztE=laAUoZx5?RC8*WKOj`%LXEkgDd>&^Q4M^z`%u0rg-It=hLCVsq!Z%^6eB-OvOT zFZ28TN&cRmgU}Elrnk43)!>Z1FCPL2K$7}gwzIc48NX}#!A1BpJP?#v5wkNprhV** z?Cpalt1oH&{r!o3eSKc&ap)iz2BTn_VV`4>9M^b3;(YY}4>#ML6{~(4mH+?%07*qo IM6N<$f(jP3KmY&$ literal 0 HcmV?d00001 diff --git a/assets/javascripts/bundle.d7c377c4.min.js b/assets/javascripts/bundle.d7c377c4.min.js new file mode 100644 index 0000000..6a0bcf8 --- /dev/null +++ b/assets/javascripts/bundle.d7c377c4.min.js @@ -0,0 +1,29 @@ +"use strict";(()=>{var Mi=Object.create;var gr=Object.defineProperty;var Li=Object.getOwnPropertyDescriptor;var _i=Object.getOwnPropertyNames,Ft=Object.getOwnPropertySymbols,Ai=Object.getPrototypeOf,xr=Object.prototype.hasOwnProperty,ro=Object.prototype.propertyIsEnumerable;var to=(e,t,r)=>t in e?gr(e,t,{enumerable:!0,configurable:!0,writable:!0,value:r}):e[t]=r,P=(e,t)=>{for(var r in t||(t={}))xr.call(t,r)&&to(e,r,t[r]);if(Ft)for(var r of Ft(t))ro.call(t,r)&&to(e,r,t[r]);return e};var oo=(e,t)=>{var r={};for(var o in e)xr.call(e,o)&&t.indexOf(o)<0&&(r[o]=e[o]);if(e!=null&&Ft)for(var o of Ft(e))t.indexOf(o)<0&&ro.call(e,o)&&(r[o]=e[o]);return r};var yr=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports);var Ci=(e,t,r,o)=>{if(t&&typeof t=="object"||typeof t=="function")for(let n of _i(t))!xr.call(e,n)&&n!==r&&gr(e,n,{get:()=>t[n],enumerable:!(o=Li(t,n))||o.enumerable});return e};var jt=(e,t,r)=>(r=e!=null?Mi(Ai(e)):{},Ci(t||!e||!e.__esModule?gr(r,"default",{value:e,enumerable:!0}):r,e));var no=(e,t,r)=>new Promise((o,n)=>{var i=c=>{try{a(r.next(c))}catch(p){n(p)}},s=c=>{try{a(r.throw(c))}catch(p){n(p)}},a=c=>c.done?o(c.value):Promise.resolve(c.value).then(i,s);a((r=r.apply(e,t)).next())});var ao=yr((Er,io)=>{(function(e,t){typeof Er=="object"&&typeof io!="undefined"?t():typeof define=="function"&&define.amd?define(t):t()})(Er,function(){"use strict";function e(r){var o=!0,n=!1,i=null,s={text:!0,search:!0,url:!0,tel:!0,email:!0,password:!0,number:!0,date:!0,month:!0,week:!0,time:!0,datetime:!0,"datetime-local":!0};function a(C){return!!(C&&C!==document&&C.nodeName!=="HTML"&&C.nodeName!=="BODY"&&"classList"in C&&"contains"in C.classList)}function c(C){var ct=C.type,Ve=C.tagName;return!!(Ve==="INPUT"&&s[ct]&&!C.readOnly||Ve==="TEXTAREA"&&!C.readOnly||C.isContentEditable)}function p(C){C.classList.contains("focus-visible")||(C.classList.add("focus-visible"),C.setAttribute("data-focus-visible-added",""))}function l(C){C.hasAttribute("data-focus-visible-added")&&(C.classList.remove("focus-visible"),C.removeAttribute("data-focus-visible-added"))}function f(C){C.metaKey||C.altKey||C.ctrlKey||(a(r.activeElement)&&p(r.activeElement),o=!0)}function u(C){o=!1}function d(C){a(C.target)&&(o||c(C.target))&&p(C.target)}function y(C){a(C.target)&&(C.target.classList.contains("focus-visible")||C.target.hasAttribute("data-focus-visible-added"))&&(n=!0,window.clearTimeout(i),i=window.setTimeout(function(){n=!1},100),l(C.target))}function b(C){document.visibilityState==="hidden"&&(n&&(o=!0),D())}function D(){document.addEventListener("mousemove",J),document.addEventListener("mousedown",J),document.addEventListener("mouseup",J),document.addEventListener("pointermove",J),document.addEventListener("pointerdown",J),document.addEventListener("pointerup",J),document.addEventListener("touchmove",J),document.addEventListener("touchstart",J),document.addEventListener("touchend",J)}function Q(){document.removeEventListener("mousemove",J),document.removeEventListener("mousedown",J),document.removeEventListener("mouseup",J),document.removeEventListener("pointermove",J),document.removeEventListener("pointerdown",J),document.removeEventListener("pointerup",J),document.removeEventListener("touchmove",J),document.removeEventListener("touchstart",J),document.removeEventListener("touchend",J)}function J(C){C.target.nodeName&&C.target.nodeName.toLowerCase()==="html"||(o=!1,Q())}document.addEventListener("keydown",f,!0),document.addEventListener("mousedown",u,!0),document.addEventListener("pointerdown",u,!0),document.addEventListener("touchstart",u,!0),document.addEventListener("visibilitychange",b,!0),D(),r.addEventListener("focus",d,!0),r.addEventListener("blur",y,!0),r.nodeType===Node.DOCUMENT_FRAGMENT_NODE&&r.host?r.host.setAttribute("data-js-focus-visible",""):r.nodeType===Node.DOCUMENT_NODE&&(document.documentElement.classList.add("js-focus-visible"),document.documentElement.setAttribute("data-js-focus-visible",""))}if(typeof window!="undefined"&&typeof document!="undefined"){window.applyFocusVisiblePolyfill=e;var t;try{t=new CustomEvent("focus-visible-polyfill-ready")}catch(r){t=document.createEvent("CustomEvent"),t.initCustomEvent("focus-visible-polyfill-ready",!1,!1,{})}window.dispatchEvent(t)}typeof document!="undefined"&&e(document)})});var Kr=yr((kt,qr)=>{/*! + * clipboard.js v2.0.11 + * https://clipboardjs.com/ + * + * Licensed MIT © Zeno Rocha + */(function(t,r){typeof kt=="object"&&typeof qr=="object"?qr.exports=r():typeof define=="function"&&define.amd?define([],r):typeof kt=="object"?kt.ClipboardJS=r():t.ClipboardJS=r()})(kt,function(){return function(){var e={686:function(o,n,i){"use strict";i.d(n,{default:function(){return Oi}});var s=i(279),a=i.n(s),c=i(370),p=i.n(c),l=i(817),f=i.n(l);function u(V){try{return document.execCommand(V)}catch(_){return!1}}var d=function(_){var O=f()(_);return u("cut"),O},y=d;function b(V){var _=document.documentElement.getAttribute("dir")==="rtl",O=document.createElement("textarea");O.style.fontSize="12pt",O.style.border="0",O.style.padding="0",O.style.margin="0",O.style.position="absolute",O.style[_?"right":"left"]="-9999px";var $=window.pageYOffset||document.documentElement.scrollTop;return O.style.top="".concat($,"px"),O.setAttribute("readonly",""),O.value=V,O}var D=function(_,O){var $=b(_);O.container.appendChild($);var N=f()($);return u("copy"),$.remove(),N},Q=function(_){var O=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{container:document.body},$="";return typeof _=="string"?$=D(_,O):_ instanceof HTMLInputElement&&!["text","search","url","tel","password"].includes(_==null?void 0:_.type)?$=D(_.value,O):($=f()(_),u("copy")),$},J=Q;function C(V){"@babel/helpers - typeof";return typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?C=function(O){return typeof O}:C=function(O){return O&&typeof Symbol=="function"&&O.constructor===Symbol&&O!==Symbol.prototype?"symbol":typeof O},C(V)}var ct=function(){var _=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{},O=_.action,$=O===void 0?"copy":O,N=_.container,Y=_.target,ke=_.text;if($!=="copy"&&$!=="cut")throw new Error('Invalid "action" value, use either "copy" or "cut"');if(Y!==void 0)if(Y&&C(Y)==="object"&&Y.nodeType===1){if($==="copy"&&Y.hasAttribute("disabled"))throw new Error('Invalid "target" attribute. Please use "readonly" instead of "disabled" attribute');if($==="cut"&&(Y.hasAttribute("readonly")||Y.hasAttribute("disabled")))throw new Error(`Invalid "target" attribute. You can't cut text from elements with "readonly" or "disabled" attributes`)}else throw new Error('Invalid "target" value, use a valid Element');if(ke)return J(ke,{container:N});if(Y)return $==="cut"?y(Y):J(Y,{container:N})},Ve=ct;function Fe(V){"@babel/helpers - typeof";return typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?Fe=function(O){return typeof O}:Fe=function(O){return O&&typeof Symbol=="function"&&O.constructor===Symbol&&O!==Symbol.prototype?"symbol":typeof O},Fe(V)}function vi(V,_){if(!(V instanceof _))throw new TypeError("Cannot call a class as a function")}function eo(V,_){for(var O=0;O<_.length;O++){var $=_[O];$.enumerable=$.enumerable||!1,$.configurable=!0,"value"in $&&($.writable=!0),Object.defineProperty(V,$.key,$)}}function gi(V,_,O){return _&&eo(V.prototype,_),O&&eo(V,O),V}function xi(V,_){if(typeof _!="function"&&_!==null)throw new TypeError("Super expression must either be null or a function");V.prototype=Object.create(_&&_.prototype,{constructor:{value:V,writable:!0,configurable:!0}}),_&&br(V,_)}function br(V,_){return br=Object.setPrototypeOf||function($,N){return $.__proto__=N,$},br(V,_)}function yi(V){var _=Ti();return function(){var $=Rt(V),N;if(_){var Y=Rt(this).constructor;N=Reflect.construct($,arguments,Y)}else N=$.apply(this,arguments);return Ei(this,N)}}function Ei(V,_){return _&&(Fe(_)==="object"||typeof _=="function")?_:wi(V)}function wi(V){if(V===void 0)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return V}function Ti(){if(typeof Reflect=="undefined"||!Reflect.construct||Reflect.construct.sham)return!1;if(typeof Proxy=="function")return!0;try{return Date.prototype.toString.call(Reflect.construct(Date,[],function(){})),!0}catch(V){return!1}}function Rt(V){return Rt=Object.setPrototypeOf?Object.getPrototypeOf:function(O){return O.__proto__||Object.getPrototypeOf(O)},Rt(V)}function vr(V,_){var O="data-clipboard-".concat(V);if(_.hasAttribute(O))return _.getAttribute(O)}var Si=function(V){xi(O,V);var _=yi(O);function O($,N){var Y;return vi(this,O),Y=_.call(this),Y.resolveOptions(N),Y.listenClick($),Y}return gi(O,[{key:"resolveOptions",value:function(){var N=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{};this.action=typeof N.action=="function"?N.action:this.defaultAction,this.target=typeof N.target=="function"?N.target:this.defaultTarget,this.text=typeof N.text=="function"?N.text:this.defaultText,this.container=Fe(N.container)==="object"?N.container:document.body}},{key:"listenClick",value:function(N){var Y=this;this.listener=p()(N,"click",function(ke){return Y.onClick(ke)})}},{key:"onClick",value:function(N){var Y=N.delegateTarget||N.currentTarget,ke=this.action(Y)||"copy",It=Ve({action:ke,container:this.container,target:this.target(Y),text:this.text(Y)});this.emit(It?"success":"error",{action:ke,text:It,trigger:Y,clearSelection:function(){Y&&Y.focus(),window.getSelection().removeAllRanges()}})}},{key:"defaultAction",value:function(N){return vr("action",N)}},{key:"defaultTarget",value:function(N){var Y=vr("target",N);if(Y)return document.querySelector(Y)}},{key:"defaultText",value:function(N){return vr("text",N)}},{key:"destroy",value:function(){this.listener.destroy()}}],[{key:"copy",value:function(N){var Y=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{container:document.body};return J(N,Y)}},{key:"cut",value:function(N){return y(N)}},{key:"isSupported",value:function(){var N=arguments.length>0&&arguments[0]!==void 0?arguments[0]:["copy","cut"],Y=typeof N=="string"?[N]:N,ke=!!document.queryCommandSupported;return Y.forEach(function(It){ke=ke&&!!document.queryCommandSupported(It)}),ke}}]),O}(a()),Oi=Si},828:function(o){var n=9;if(typeof Element!="undefined"&&!Element.prototype.matches){var i=Element.prototype;i.matches=i.matchesSelector||i.mozMatchesSelector||i.msMatchesSelector||i.oMatchesSelector||i.webkitMatchesSelector}function s(a,c){for(;a&&a.nodeType!==n;){if(typeof a.matches=="function"&&a.matches(c))return a;a=a.parentNode}}o.exports=s},438:function(o,n,i){var s=i(828);function a(l,f,u,d,y){var b=p.apply(this,arguments);return l.addEventListener(u,b,y),{destroy:function(){l.removeEventListener(u,b,y)}}}function c(l,f,u,d,y){return typeof l.addEventListener=="function"?a.apply(null,arguments):typeof u=="function"?a.bind(null,document).apply(null,arguments):(typeof l=="string"&&(l=document.querySelectorAll(l)),Array.prototype.map.call(l,function(b){return a(b,f,u,d,y)}))}function p(l,f,u,d){return function(y){y.delegateTarget=s(y.target,f),y.delegateTarget&&d.call(l,y)}}o.exports=c},879:function(o,n){n.node=function(i){return i!==void 0&&i instanceof HTMLElement&&i.nodeType===1},n.nodeList=function(i){var s=Object.prototype.toString.call(i);return i!==void 0&&(s==="[object NodeList]"||s==="[object HTMLCollection]")&&"length"in i&&(i.length===0||n.node(i[0]))},n.string=function(i){return typeof i=="string"||i instanceof String},n.fn=function(i){var s=Object.prototype.toString.call(i);return s==="[object Function]"}},370:function(o,n,i){var s=i(879),a=i(438);function c(u,d,y){if(!u&&!d&&!y)throw new Error("Missing required arguments");if(!s.string(d))throw new TypeError("Second argument must be a String");if(!s.fn(y))throw new TypeError("Third argument must be a Function");if(s.node(u))return p(u,d,y);if(s.nodeList(u))return l(u,d,y);if(s.string(u))return f(u,d,y);throw new TypeError("First argument must be a String, HTMLElement, HTMLCollection, or NodeList")}function p(u,d,y){return u.addEventListener(d,y),{destroy:function(){u.removeEventListener(d,y)}}}function l(u,d,y){return Array.prototype.forEach.call(u,function(b){b.addEventListener(d,y)}),{destroy:function(){Array.prototype.forEach.call(u,function(b){b.removeEventListener(d,y)})}}}function f(u,d,y){return a(document.body,u,d,y)}o.exports=c},817:function(o){function n(i){var s;if(i.nodeName==="SELECT")i.focus(),s=i.value;else if(i.nodeName==="INPUT"||i.nodeName==="TEXTAREA"){var a=i.hasAttribute("readonly");a||i.setAttribute("readonly",""),i.select(),i.setSelectionRange(0,i.value.length),a||i.removeAttribute("readonly"),s=i.value}else{i.hasAttribute("contenteditable")&&i.focus();var c=window.getSelection(),p=document.createRange();p.selectNodeContents(i),c.removeAllRanges(),c.addRange(p),s=c.toString()}return s}o.exports=n},279:function(o){function n(){}n.prototype={on:function(i,s,a){var c=this.e||(this.e={});return(c[i]||(c[i]=[])).push({fn:s,ctx:a}),this},once:function(i,s,a){var c=this;function p(){c.off(i,p),s.apply(a,arguments)}return p._=s,this.on(i,p,a)},emit:function(i){var s=[].slice.call(arguments,1),a=((this.e||(this.e={}))[i]||[]).slice(),c=0,p=a.length;for(c;c{"use strict";/*! + * escape-html + * Copyright(c) 2012-2013 TJ Holowaychuk + * Copyright(c) 2015 Andreas Lubbe + * Copyright(c) 2015 Tiancheng "Timothy" Gu + * MIT Licensed + */var Wa=/["'&<>]/;Vn.exports=Ua;function Ua(e){var t=""+e,r=Wa.exec(t);if(!r)return t;var o,n="",i=0,s=0;for(i=r.index;i0&&i[i.length-1])&&(p[0]===6||p[0]===2)){r=0;continue}if(p[0]===3&&(!i||p[1]>i[0]&&p[1]=e.length&&(e=void 0),{value:e&&e[o++],done:!e}}};throw new TypeError(t?"Object is not iterable.":"Symbol.iterator is not defined.")}function z(e,t){var r=typeof Symbol=="function"&&e[Symbol.iterator];if(!r)return e;var o=r.call(e),n,i=[],s;try{for(;(t===void 0||t-- >0)&&!(n=o.next()).done;)i.push(n.value)}catch(a){s={error:a}}finally{try{n&&!n.done&&(r=o.return)&&r.call(o)}finally{if(s)throw s.error}}return i}function K(e,t,r){if(r||arguments.length===2)for(var o=0,n=t.length,i;o1||a(u,d)})})}function a(u,d){try{c(o[u](d))}catch(y){f(i[0][3],y)}}function c(u){u.value instanceof ot?Promise.resolve(u.value.v).then(p,l):f(i[0][2],u)}function p(u){a("next",u)}function l(u){a("throw",u)}function f(u,d){u(d),i.shift(),i.length&&a(i[0][0],i[0][1])}}function po(e){if(!Symbol.asyncIterator)throw new TypeError("Symbol.asyncIterator is not defined.");var t=e[Symbol.asyncIterator],r;return t?t.call(e):(e=typeof be=="function"?be(e):e[Symbol.iterator](),r={},o("next"),o("throw"),o("return"),r[Symbol.asyncIterator]=function(){return this},r);function o(i){r[i]=e[i]&&function(s){return new Promise(function(a,c){s=e[i](s),n(a,c,s.done,s.value)})}}function n(i,s,a,c){Promise.resolve(c).then(function(p){i({value:p,done:a})},s)}}function k(e){return typeof e=="function"}function pt(e){var t=function(o){Error.call(o),o.stack=new Error().stack},r=e(t);return r.prototype=Object.create(Error.prototype),r.prototype.constructor=r,r}var Ut=pt(function(e){return function(r){e(this),this.message=r?r.length+` errors occurred during unsubscription: +`+r.map(function(o,n){return n+1+") "+o.toString()}).join(` + `):"",this.name="UnsubscriptionError",this.errors=r}});function ze(e,t){if(e){var r=e.indexOf(t);0<=r&&e.splice(r,1)}}var je=function(){function e(t){this.initialTeardown=t,this.closed=!1,this._parentage=null,this._finalizers=null}return e.prototype.unsubscribe=function(){var t,r,o,n,i;if(!this.closed){this.closed=!0;var s=this._parentage;if(s)if(this._parentage=null,Array.isArray(s))try{for(var a=be(s),c=a.next();!c.done;c=a.next()){var p=c.value;p.remove(this)}}catch(b){t={error:b}}finally{try{c&&!c.done&&(r=a.return)&&r.call(a)}finally{if(t)throw t.error}}else s.remove(this);var l=this.initialTeardown;if(k(l))try{l()}catch(b){i=b instanceof Ut?b.errors:[b]}var f=this._finalizers;if(f){this._finalizers=null;try{for(var u=be(f),d=u.next();!d.done;d=u.next()){var y=d.value;try{lo(y)}catch(b){i=i!=null?i:[],b instanceof Ut?i=K(K([],z(i)),z(b.errors)):i.push(b)}}}catch(b){o={error:b}}finally{try{d&&!d.done&&(n=u.return)&&n.call(u)}finally{if(o)throw o.error}}}if(i)throw new Ut(i)}},e.prototype.add=function(t){var r;if(t&&t!==this)if(this.closed)lo(t);else{if(t instanceof e){if(t.closed||t._hasParent(this))return;t._addParent(this)}(this._finalizers=(r=this._finalizers)!==null&&r!==void 0?r:[]).push(t)}},e.prototype._hasParent=function(t){var r=this._parentage;return r===t||Array.isArray(r)&&r.includes(t)},e.prototype._addParent=function(t){var r=this._parentage;this._parentage=Array.isArray(r)?(r.push(t),r):r?[r,t]:t},e.prototype._removeParent=function(t){var r=this._parentage;r===t?this._parentage=null:Array.isArray(r)&&ze(r,t)},e.prototype.remove=function(t){var r=this._finalizers;r&&ze(r,t),t instanceof e&&t._removeParent(this)},e.EMPTY=function(){var t=new e;return t.closed=!0,t}(),e}();var Tr=je.EMPTY;function Nt(e){return e instanceof je||e&&"closed"in e&&k(e.remove)&&k(e.add)&&k(e.unsubscribe)}function lo(e){k(e)?e():e.unsubscribe()}var He={onUnhandledError:null,onStoppedNotification:null,Promise:void 0,useDeprecatedSynchronousErrorHandling:!1,useDeprecatedNextContext:!1};var lt={setTimeout:function(e,t){for(var r=[],o=2;o0},enumerable:!1,configurable:!0}),t.prototype._trySubscribe=function(r){return this._throwIfClosed(),e.prototype._trySubscribe.call(this,r)},t.prototype._subscribe=function(r){return this._throwIfClosed(),this._checkFinalizedStatuses(r),this._innerSubscribe(r)},t.prototype._innerSubscribe=function(r){var o=this,n=this,i=n.hasError,s=n.isStopped,a=n.observers;return i||s?Tr:(this.currentObservers=null,a.push(r),new je(function(){o.currentObservers=null,ze(a,r)}))},t.prototype._checkFinalizedStatuses=function(r){var o=this,n=o.hasError,i=o.thrownError,s=o.isStopped;n?r.error(i):s&&r.complete()},t.prototype.asObservable=function(){var r=new I;return r.source=this,r},t.create=function(r,o){return new xo(r,o)},t}(I);var xo=function(e){se(t,e);function t(r,o){var n=e.call(this)||this;return n.destination=r,n.source=o,n}return t.prototype.next=function(r){var o,n;(n=(o=this.destination)===null||o===void 0?void 0:o.next)===null||n===void 0||n.call(o,r)},t.prototype.error=function(r){var o,n;(n=(o=this.destination)===null||o===void 0?void 0:o.error)===null||n===void 0||n.call(o,r)},t.prototype.complete=function(){var r,o;(o=(r=this.destination)===null||r===void 0?void 0:r.complete)===null||o===void 0||o.call(r)},t.prototype._subscribe=function(r){var o,n;return(n=(o=this.source)===null||o===void 0?void 0:o.subscribe(r))!==null&&n!==void 0?n:Tr},t}(x);var St={now:function(){return(St.delegate||Date).now()},delegate:void 0};var Ot=function(e){se(t,e);function t(r,o,n){r===void 0&&(r=1/0),o===void 0&&(o=1/0),n===void 0&&(n=St);var i=e.call(this)||this;return i._bufferSize=r,i._windowTime=o,i._timestampProvider=n,i._buffer=[],i._infiniteTimeWindow=!0,i._infiniteTimeWindow=o===1/0,i._bufferSize=Math.max(1,r),i._windowTime=Math.max(1,o),i}return t.prototype.next=function(r){var o=this,n=o.isStopped,i=o._buffer,s=o._infiniteTimeWindow,a=o._timestampProvider,c=o._windowTime;n||(i.push(r),!s&&i.push(a.now()+c)),this._trimBuffer(),e.prototype.next.call(this,r)},t.prototype._subscribe=function(r){this._throwIfClosed(),this._trimBuffer();for(var o=this._innerSubscribe(r),n=this,i=n._infiniteTimeWindow,s=n._buffer,a=s.slice(),c=0;c0?e.prototype.requestAsyncId.call(this,r,o,n):(r.actions.push(this),r._scheduled||(r._scheduled=ut.requestAnimationFrame(function(){return r.flush(void 0)})))},t.prototype.recycleAsyncId=function(r,o,n){var i;if(n===void 0&&(n=0),n!=null?n>0:this.delay>0)return e.prototype.recycleAsyncId.call(this,r,o,n);var s=r.actions;o!=null&&((i=s[s.length-1])===null||i===void 0?void 0:i.id)!==o&&(ut.cancelAnimationFrame(o),r._scheduled=void 0)},t}(zt);var wo=function(e){se(t,e);function t(){return e!==null&&e.apply(this,arguments)||this}return t.prototype.flush=function(r){this._active=!0;var o=this._scheduled;this._scheduled=void 0;var n=this.actions,i;r=r||n.shift();do if(i=r.execute(r.state,r.delay))break;while((r=n[0])&&r.id===o&&n.shift());if(this._active=!1,i){for(;(r=n[0])&&r.id===o&&n.shift();)r.unsubscribe();throw i}},t}(qt);var ge=new wo(Eo);var M=new I(function(e){return e.complete()});function Kt(e){return e&&k(e.schedule)}function Cr(e){return e[e.length-1]}function Ge(e){return k(Cr(e))?e.pop():void 0}function Ae(e){return Kt(Cr(e))?e.pop():void 0}function Qt(e,t){return typeof Cr(e)=="number"?e.pop():t}var dt=function(e){return e&&typeof e.length=="number"&&typeof e!="function"};function Yt(e){return k(e==null?void 0:e.then)}function Bt(e){return k(e[ft])}function Gt(e){return Symbol.asyncIterator&&k(e==null?void 0:e[Symbol.asyncIterator])}function Jt(e){return new TypeError("You provided "+(e!==null&&typeof e=="object"?"an invalid object":"'"+e+"'")+" where a stream was expected. You can provide an Observable, Promise, ReadableStream, Array, AsyncIterable, or Iterable.")}function Wi(){return typeof Symbol!="function"||!Symbol.iterator?"@@iterator":Symbol.iterator}var Xt=Wi();function Zt(e){return k(e==null?void 0:e[Xt])}function er(e){return co(this,arguments,function(){var r,o,n,i;return Wt(this,function(s){switch(s.label){case 0:r=e.getReader(),s.label=1;case 1:s.trys.push([1,,9,10]),s.label=2;case 2:return[4,ot(r.read())];case 3:return o=s.sent(),n=o.value,i=o.done,i?[4,ot(void 0)]:[3,5];case 4:return[2,s.sent()];case 5:return[4,ot(n)];case 6:return[4,s.sent()];case 7:return s.sent(),[3,2];case 8:return[3,10];case 9:return r.releaseLock(),[7];case 10:return[2]}})})}function tr(e){return k(e==null?void 0:e.getReader)}function F(e){if(e instanceof I)return e;if(e!=null){if(Bt(e))return Ui(e);if(dt(e))return Ni(e);if(Yt(e))return Di(e);if(Gt(e))return To(e);if(Zt(e))return Vi(e);if(tr(e))return zi(e)}throw Jt(e)}function Ui(e){return new I(function(t){var r=e[ft]();if(k(r.subscribe))return r.subscribe(t);throw new TypeError("Provided object does not correctly implement Symbol.observable")})}function Ni(e){return new I(function(t){for(var r=0;r=2;return function(o){return o.pipe(e?v(function(n,i){return e(n,i,o)}):pe,ue(1),r?$e(t):Uo(function(){return new or}))}}function Rr(e){return e<=0?function(){return M}:g(function(t,r){var o=[];t.subscribe(E(r,function(n){o.push(n),e=2,!0))}function de(e){e===void 0&&(e={});var t=e.connector,r=t===void 0?function(){return new x}:t,o=e.resetOnError,n=o===void 0?!0:o,i=e.resetOnComplete,s=i===void 0?!0:i,a=e.resetOnRefCountZero,c=a===void 0?!0:a;return function(p){var l,f,u,d=0,y=!1,b=!1,D=function(){f==null||f.unsubscribe(),f=void 0},Q=function(){D(),l=u=void 0,y=b=!1},J=function(){var C=l;Q(),C==null||C.unsubscribe()};return g(function(C,ct){d++,!b&&!y&&D();var Ve=u=u!=null?u:r();ct.add(function(){d--,d===0&&!b&&!y&&(f=jr(J,c))}),Ve.subscribe(ct),!l&&d>0&&(l=new it({next:function(Fe){return Ve.next(Fe)},error:function(Fe){b=!0,D(),f=jr(Q,n,Fe),Ve.error(Fe)},complete:function(){y=!0,D(),f=jr(Q,s),Ve.complete()}}),F(C).subscribe(l))})(p)}}function jr(e,t){for(var r=[],o=2;oe.next(document)),e}function W(e,t=document){return Array.from(t.querySelectorAll(e))}function U(e,t=document){let r=ce(e,t);if(typeof r=="undefined")throw new ReferenceError(`Missing element: expected "${e}" to be present`);return r}function ce(e,t=document){return t.querySelector(e)||void 0}function Ie(){return document.activeElement instanceof HTMLElement&&document.activeElement||void 0}var ca=L(h(document.body,"focusin"),h(document.body,"focusout")).pipe(ye(1),q(void 0),m(()=>Ie()||document.body),Z(1));function vt(e){return ca.pipe(m(t=>e.contains(t)),X())}function qo(e,t){return L(h(e,"mouseenter").pipe(m(()=>!0)),h(e,"mouseleave").pipe(m(()=>!1))).pipe(t?ye(t):pe,q(!1))}function Ue(e){return{x:e.offsetLeft,y:e.offsetTop}}function Ko(e){return L(h(window,"load"),h(window,"resize")).pipe(Le(0,ge),m(()=>Ue(e)),q(Ue(e)))}function ir(e){return{x:e.scrollLeft,y:e.scrollTop}}function et(e){return L(h(e,"scroll"),h(window,"resize")).pipe(Le(0,ge),m(()=>ir(e)),q(ir(e)))}function Qo(e,t){if(typeof t=="string"||typeof t=="number")e.innerHTML+=t.toString();else if(t instanceof Node)e.appendChild(t);else if(Array.isArray(t))for(let r of t)Qo(e,r)}function S(e,t,...r){let o=document.createElement(e);if(t)for(let n of Object.keys(t))typeof t[n]!="undefined"&&(typeof t[n]!="boolean"?o.setAttribute(n,t[n]):o.setAttribute(n,""));for(let n of r)Qo(o,n);return o}function ar(e){if(e>999){let t=+((e-950)%1e3>99);return`${((e+1e-6)/1e3).toFixed(t)}k`}else return e.toString()}function gt(e){let t=S("script",{src:e});return H(()=>(document.head.appendChild(t),L(h(t,"load"),h(t,"error").pipe(w(()=>kr(()=>new ReferenceError(`Invalid script: ${e}`))))).pipe(m(()=>{}),A(()=>document.head.removeChild(t)),ue(1))))}var Yo=new x,pa=H(()=>typeof ResizeObserver=="undefined"?gt("https://unpkg.com/resize-observer-polyfill"):R(void 0)).pipe(m(()=>new ResizeObserver(e=>{for(let t of e)Yo.next(t)})),w(e=>L(Ke,R(e)).pipe(A(()=>e.disconnect()))),Z(1));function le(e){return{width:e.offsetWidth,height:e.offsetHeight}}function Se(e){return pa.pipe(T(t=>t.observe(e)),w(t=>Yo.pipe(v(({target:r})=>r===e),A(()=>t.unobserve(e)),m(()=>le(e)))),q(le(e)))}function xt(e){return{width:e.scrollWidth,height:e.scrollHeight}}function sr(e){let t=e.parentElement;for(;t&&(e.scrollWidth<=t.scrollWidth&&e.scrollHeight<=t.scrollHeight);)t=(e=t).parentElement;return t?e:void 0}var Bo=new x,la=H(()=>R(new IntersectionObserver(e=>{for(let t of e)Bo.next(t)},{threshold:0}))).pipe(w(e=>L(Ke,R(e)).pipe(A(()=>e.disconnect()))),Z(1));function yt(e){return la.pipe(T(t=>t.observe(e)),w(t=>Bo.pipe(v(({target:r})=>r===e),A(()=>t.unobserve(e)),m(({isIntersecting:r})=>r))))}function Go(e,t=16){return et(e).pipe(m(({y:r})=>{let o=le(e),n=xt(e);return r>=n.height-o.height-t}),X())}var cr={drawer:U("[data-md-toggle=drawer]"),search:U("[data-md-toggle=search]")};function Jo(e){return cr[e].checked}function Ye(e,t){cr[e].checked!==t&&cr[e].click()}function Ne(e){let t=cr[e];return h(t,"change").pipe(m(()=>t.checked),q(t.checked))}function ma(e,t){switch(e.constructor){case HTMLInputElement:return e.type==="radio"?/^Arrow/.test(t):!0;case HTMLSelectElement:case HTMLTextAreaElement:return!0;default:return e.isContentEditable}}function fa(){return L(h(window,"compositionstart").pipe(m(()=>!0)),h(window,"compositionend").pipe(m(()=>!1))).pipe(q(!1))}function Xo(){let e=h(window,"keydown").pipe(v(t=>!(t.metaKey||t.ctrlKey)),m(t=>({mode:Jo("search")?"search":"global",type:t.key,claim(){t.preventDefault(),t.stopPropagation()}})),v(({mode:t,type:r})=>{if(t==="global"){let o=Ie();if(typeof o!="undefined")return!ma(o,r)}return!0}),de());return fa().pipe(w(t=>t?M:e))}function me(){return new URL(location.href)}function st(e,t=!1){if(G("navigation.instant")&&!t){let r=S("a",{href:e.href});document.body.appendChild(r),r.click(),r.remove()}else location.href=e.href}function Zo(){return new x}function en(){return location.hash.slice(1)}function pr(e){let t=S("a",{href:e});t.addEventListener("click",r=>r.stopPropagation()),t.click()}function ua(e){return L(h(window,"hashchange"),e).pipe(m(en),q(en()),v(t=>t.length>0),Z(1))}function tn(e){return ua(e).pipe(m(t=>ce(`[id="${t}"]`)),v(t=>typeof t!="undefined"))}function At(e){let t=matchMedia(e);return nr(r=>t.addListener(()=>r(t.matches))).pipe(q(t.matches))}function rn(){let e=matchMedia("print");return L(h(window,"beforeprint").pipe(m(()=>!0)),h(window,"afterprint").pipe(m(()=>!1))).pipe(q(e.matches))}function Dr(e,t){return e.pipe(w(r=>r?t():M))}function lr(e,t){return new I(r=>{let o=new XMLHttpRequest;o.open("GET",`${e}`),o.responseType="blob",o.addEventListener("load",()=>{o.status>=200&&o.status<300?(r.next(o.response),r.complete()):r.error(new Error(o.statusText))}),o.addEventListener("error",()=>{r.error(new Error("Network Error"))}),o.addEventListener("abort",()=>{r.error(new Error("Request aborted"))}),typeof(t==null?void 0:t.progress$)!="undefined"&&(o.addEventListener("progress",n=>{if(n.lengthComputable)t.progress$.next(n.loaded/n.total*100);else{let i=Number(o.getResponseHeader("Content-Length"))||0;t.progress$.next(n.loaded/i*100)}}),t.progress$.next(5)),o.send()})}function De(e,t){return lr(e,t).pipe(w(r=>r.text()),m(r=>JSON.parse(r)),Z(1))}function on(e,t){let r=new DOMParser;return lr(e,t).pipe(w(o=>o.text()),m(o=>r.parseFromString(o,"text/xml")),Z(1))}function nn(){return{x:Math.max(0,scrollX),y:Math.max(0,scrollY)}}function an(){return L(h(window,"scroll",{passive:!0}),h(window,"resize",{passive:!0})).pipe(m(nn),q(nn()))}function sn(){return{width:innerWidth,height:innerHeight}}function cn(){return h(window,"resize",{passive:!0}).pipe(m(sn),q(sn()))}function pn(){return B([an(),cn()]).pipe(m(([e,t])=>({offset:e,size:t})),Z(1))}function mr(e,{viewport$:t,header$:r}){let o=t.pipe(te("size")),n=B([o,r]).pipe(m(()=>Ue(e)));return B([r,t,n]).pipe(m(([{height:i},{offset:s,size:a},{x:c,y:p}])=>({offset:{x:s.x-c,y:s.y-p+i},size:a})))}function da(e){return h(e,"message",t=>t.data)}function ha(e){let t=new x;return t.subscribe(r=>e.postMessage(r)),t}function ln(e,t=new Worker(e)){let r=da(t),o=ha(t),n=new x;n.subscribe(o);let i=o.pipe(ee(),oe(!0));return n.pipe(ee(),Re(r.pipe(j(i))),de())}var ba=U("#__config"),Et=JSON.parse(ba.textContent);Et.base=`${new URL(Et.base,me())}`;function he(){return Et}function G(e){return Et.features.includes(e)}function we(e,t){return typeof t!="undefined"?Et.translations[e].replace("#",t.toString()):Et.translations[e]}function Oe(e,t=document){return U(`[data-md-component=${e}]`,t)}function ne(e,t=document){return W(`[data-md-component=${e}]`,t)}function va(e){let t=U(".md-typeset > :first-child",e);return h(t,"click",{once:!0}).pipe(m(()=>U(".md-typeset",e)),m(r=>({hash:__md_hash(r.innerHTML)})))}function mn(e){if(!G("announce.dismiss")||!e.childElementCount)return M;if(!e.hidden){let t=U(".md-typeset",e);__md_hash(t.innerHTML)===__md_get("__announce")&&(e.hidden=!0)}return H(()=>{let t=new x;return t.subscribe(({hash:r})=>{e.hidden=!0,__md_set("__announce",r)}),va(e).pipe(T(r=>t.next(r)),A(()=>t.complete()),m(r=>P({ref:e},r)))})}function ga(e,{target$:t}){return t.pipe(m(r=>({hidden:r!==e})))}function fn(e,t){let r=new x;return r.subscribe(({hidden:o})=>{e.hidden=o}),ga(e,t).pipe(T(o=>r.next(o)),A(()=>r.complete()),m(o=>P({ref:e},o)))}function Ct(e,t){return t==="inline"?S("div",{class:"md-tooltip md-tooltip--inline",id:e,role:"tooltip"},S("div",{class:"md-tooltip__inner md-typeset"})):S("div",{class:"md-tooltip",id:e,role:"tooltip"},S("div",{class:"md-tooltip__inner md-typeset"}))}function un(e,t){if(t=t?`${t}_annotation_${e}`:void 0,t){let r=t?`#${t}`:void 0;return S("aside",{class:"md-annotation",tabIndex:0},Ct(t),S("a",{href:r,class:"md-annotation__index",tabIndex:-1},S("span",{"data-md-annotation-id":e})))}else return S("aside",{class:"md-annotation",tabIndex:0},Ct(t),S("span",{class:"md-annotation__index",tabIndex:-1},S("span",{"data-md-annotation-id":e})))}function dn(e){return S("button",{class:"md-clipboard md-icon",title:we("clipboard.copy"),"data-clipboard-target":`#${e} > code`})}function Vr(e,t){let r=t&2,o=t&1,n=Object.keys(e.terms).filter(c=>!e.terms[c]).reduce((c,p)=>[...c,S("del",null,p)," "],[]).slice(0,-1),i=he(),s=new URL(e.location,i.base);G("search.highlight")&&s.searchParams.set("h",Object.entries(e.terms).filter(([,c])=>c).reduce((c,[p])=>`${c} ${p}`.trim(),""));let{tags:a}=he();return S("a",{href:`${s}`,class:"md-search-result__link",tabIndex:-1},S("article",{class:"md-search-result__article md-typeset","data-md-score":e.score.toFixed(2)},r>0&&S("div",{class:"md-search-result__icon md-icon"}),r>0&&S("h1",null,e.title),r<=0&&S("h2",null,e.title),o>0&&e.text.length>0&&e.text,e.tags&&e.tags.map(c=>{let p=a?c in a?`md-tag-icon md-tag--${a[c]}`:"md-tag-icon":"";return S("span",{class:`md-tag ${p}`},c)}),o>0&&n.length>0&&S("p",{class:"md-search-result__terms"},we("search.result.term.missing"),": ",...n)))}function hn(e){let t=e[0].score,r=[...e],o=he(),n=r.findIndex(l=>!`${new URL(l.location,o.base)}`.includes("#")),[i]=r.splice(n,1),s=r.findIndex(l=>l.scoreVr(l,1)),...c.length?[S("details",{class:"md-search-result__more"},S("summary",{tabIndex:-1},S("div",null,c.length>0&&c.length===1?we("search.result.more.one"):we("search.result.more.other",c.length))),...c.map(l=>Vr(l,1)))]:[]];return S("li",{class:"md-search-result__item"},p)}function bn(e){return S("ul",{class:"md-source__facts"},Object.entries(e).map(([t,r])=>S("li",{class:`md-source__fact md-source__fact--${t}`},typeof r=="number"?ar(r):r)))}function zr(e){let t=`tabbed-control tabbed-control--${e}`;return S("div",{class:t,hidden:!0},S("button",{class:"tabbed-button",tabIndex:-1,"aria-hidden":"true"}))}function vn(e){return S("div",{class:"md-typeset__scrollwrap"},S("div",{class:"md-typeset__table"},e))}function xa(e){let t=he(),r=new URL(`../${e.version}/`,t.base);return S("li",{class:"md-version__item"},S("a",{href:`${r}`,class:"md-version__link"},e.title))}function gn(e,t){return S("div",{class:"md-version"},S("button",{class:"md-version__current","aria-label":we("select.version")},t.title),S("ul",{class:"md-version__list"},e.map(xa)))}var ya=0;function Ea(e,t){document.body.append(e);let{width:r}=le(e);e.style.setProperty("--md-tooltip-width",`${r}px`),e.remove();let o=sr(t),n=typeof o!="undefined"?et(o):R({x:0,y:0}),i=L(vt(t),qo(t)).pipe(X());return B([i,n]).pipe(m(([s,a])=>{let{x:c,y:p}=Ue(t),l=le(t),f=t.closest("table");return f&&t.parentElement&&(c+=f.offsetLeft+t.parentElement.offsetLeft,p+=f.offsetTop+t.parentElement.offsetTop),{active:s,offset:{x:c-a.x+l.width/2-r/2,y:p-a.y+l.height+8}}}))}function Be(e){let t=e.title;if(!t.length)return M;let r=`__tooltip_${ya++}`,o=Ct(r,"inline"),n=U(".md-typeset",o);return n.innerHTML=t,H(()=>{let i=new x;return i.subscribe({next({offset:s}){o.style.setProperty("--md-tooltip-x",`${s.x}px`),o.style.setProperty("--md-tooltip-y",`${s.y}px`)},complete(){o.style.removeProperty("--md-tooltip-x"),o.style.removeProperty("--md-tooltip-y")}}),L(i.pipe(v(({active:s})=>s)),i.pipe(ye(250),v(({active:s})=>!s))).subscribe({next({active:s}){s?(e.insertAdjacentElement("afterend",o),e.setAttribute("aria-describedby",r),e.removeAttribute("title")):(o.remove(),e.removeAttribute("aria-describedby"),e.setAttribute("title",t))},complete(){o.remove(),e.removeAttribute("aria-describedby"),e.setAttribute("title",t)}}),i.pipe(Le(16,ge)).subscribe(({active:s})=>{o.classList.toggle("md-tooltip--active",s)}),i.pipe(_t(125,ge),v(()=>!!e.offsetParent),m(()=>e.offsetParent.getBoundingClientRect()),m(({x:s})=>s)).subscribe({next(s){s?o.style.setProperty("--md-tooltip-0",`${-s}px`):o.style.removeProperty("--md-tooltip-0")},complete(){o.style.removeProperty("--md-tooltip-0")}}),Ea(o,e).pipe(T(s=>i.next(s)),A(()=>i.complete()),m(s=>P({ref:e},s)))}).pipe(qe(ie))}function wa(e,t){let r=H(()=>B([Ko(e),et(t)])).pipe(m(([{x:o,y:n},i])=>{let{width:s,height:a}=le(e);return{x:o-i.x+s/2,y:n-i.y+a/2}}));return vt(e).pipe(w(o=>r.pipe(m(n=>({active:o,offset:n})),ue(+!o||1/0))))}function xn(e,t,{target$:r}){let[o,n]=Array.from(e.children);return H(()=>{let i=new x,s=i.pipe(ee(),oe(!0));return i.subscribe({next({offset:a}){e.style.setProperty("--md-tooltip-x",`${a.x}px`),e.style.setProperty("--md-tooltip-y",`${a.y}px`)},complete(){e.style.removeProperty("--md-tooltip-x"),e.style.removeProperty("--md-tooltip-y")}}),yt(e).pipe(j(s)).subscribe(a=>{e.toggleAttribute("data-md-visible",a)}),L(i.pipe(v(({active:a})=>a)),i.pipe(ye(250),v(({active:a})=>!a))).subscribe({next({active:a}){a?e.prepend(o):o.remove()},complete(){e.prepend(o)}}),i.pipe(Le(16,ge)).subscribe(({active:a})=>{o.classList.toggle("md-tooltip--active",a)}),i.pipe(_t(125,ge),v(()=>!!e.offsetParent),m(()=>e.offsetParent.getBoundingClientRect()),m(({x:a})=>a)).subscribe({next(a){a?e.style.setProperty("--md-tooltip-0",`${-a}px`):e.style.removeProperty("--md-tooltip-0")},complete(){e.style.removeProperty("--md-tooltip-0")}}),h(n,"click").pipe(j(s),v(a=>!(a.metaKey||a.ctrlKey))).subscribe(a=>{a.stopPropagation(),a.preventDefault()}),h(n,"mousedown").pipe(j(s),ae(i)).subscribe(([a,{active:c}])=>{var p;if(a.button!==0||a.metaKey||a.ctrlKey)a.preventDefault();else if(c){a.preventDefault();let l=e.parentElement.closest(".md-annotation");l instanceof HTMLElement?l.focus():(p=Ie())==null||p.blur()}}),r.pipe(j(s),v(a=>a===o),Qe(125)).subscribe(()=>e.focus()),wa(e,t).pipe(T(a=>i.next(a)),A(()=>i.complete()),m(a=>P({ref:e},a)))})}function Ta(e){return e.tagName==="CODE"?W(".c, .c1, .cm",e):[e]}function Sa(e){let t=[];for(let r of Ta(e)){let o=[],n=document.createNodeIterator(r,NodeFilter.SHOW_TEXT);for(let i=n.nextNode();i;i=n.nextNode())o.push(i);for(let i of o){let s;for(;s=/(\(\d+\))(!)?/.exec(i.textContent);){let[,a,c]=s;if(typeof c=="undefined"){let p=i.splitText(s.index);i=p.splitText(a.length),t.push(p)}else{i.textContent=a,t.push(i);break}}}}return t}function yn(e,t){t.append(...Array.from(e.childNodes))}function fr(e,t,{target$:r,print$:o}){let n=t.closest("[id]"),i=n==null?void 0:n.id,s=new Map;for(let a of Sa(t)){let[,c]=a.textContent.match(/\((\d+)\)/);ce(`:scope > li:nth-child(${c})`,e)&&(s.set(c,un(c,i)),a.replaceWith(s.get(c)))}return s.size===0?M:H(()=>{let a=new x,c=a.pipe(ee(),oe(!0)),p=[];for(let[l,f]of s)p.push([U(".md-typeset",f),U(`:scope > li:nth-child(${l})`,e)]);return o.pipe(j(c)).subscribe(l=>{e.hidden=!l,e.classList.toggle("md-annotation-list",l);for(let[f,u]of p)l?yn(f,u):yn(u,f)}),L(...[...s].map(([,l])=>xn(l,t,{target$:r}))).pipe(A(()=>a.complete()),de())})}function En(e){if(e.nextElementSibling){let t=e.nextElementSibling;if(t.tagName==="OL")return t;if(t.tagName==="P"&&!t.children.length)return En(t)}}function wn(e,t){return H(()=>{let r=En(e);return typeof r!="undefined"?fr(r,e,t):M})}var Tn=jt(Kr());var Oa=0;function Sn(e){if(e.nextElementSibling){let t=e.nextElementSibling;if(t.tagName==="OL")return t;if(t.tagName==="P"&&!t.children.length)return Sn(t)}}function Ma(e){return Se(e).pipe(m(({width:t})=>({scrollable:xt(e).width>t})),te("scrollable"))}function On(e,t){let{matches:r}=matchMedia("(hover)"),o=H(()=>{let n=new x,i=n.pipe(Rr(1));n.subscribe(({scrollable:c})=>{c&&r?e.setAttribute("tabindex","0"):e.removeAttribute("tabindex")});let s=[];if(Tn.default.isSupported()&&(e.closest(".copy")||G("content.code.copy")&&!e.closest(".no-copy"))){let c=e.closest("pre");c.id=`__code_${Oa++}`;let p=dn(c.id);c.insertBefore(p,e),G("content.tooltips")&&s.push(Be(p))}let a=e.closest(".highlight");if(a instanceof HTMLElement){let c=Sn(a);if(typeof c!="undefined"&&(a.classList.contains("annotate")||G("content.code.annotate"))){let p=fr(c,e,t);s.push(Se(a).pipe(j(i),m(({width:l,height:f})=>l&&f),X(),w(l=>l?p:M)))}}return Ma(e).pipe(T(c=>n.next(c)),A(()=>n.complete()),m(c=>P({ref:e},c)),Re(...s))});return G("content.lazy")?yt(e).pipe(v(n=>n),ue(1),w(()=>o)):o}function La(e,{target$:t,print$:r}){let o=!0;return L(t.pipe(m(n=>n.closest("details:not([open])")),v(n=>e===n),m(()=>({action:"open",reveal:!0}))),r.pipe(v(n=>n||!o),T(()=>o=e.open),m(n=>({action:n?"open":"close"}))))}function Mn(e,t){return H(()=>{let r=new x;return r.subscribe(({action:o,reveal:n})=>{e.toggleAttribute("open",o==="open"),n&&e.scrollIntoView()}),La(e,t).pipe(T(o=>r.next(o)),A(()=>r.complete()),m(o=>P({ref:e},o)))})}var Ln=".node circle,.node ellipse,.node path,.node polygon,.node rect{fill:var(--md-mermaid-node-bg-color);stroke:var(--md-mermaid-node-fg-color)}marker{fill:var(--md-mermaid-edge-color)!important}.edgeLabel .label rect{fill:#0000}.label{color:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}.label foreignObject{line-height:normal;overflow:visible}.label div .edgeLabel{color:var(--md-mermaid-label-fg-color)}.edgeLabel,.edgeLabel rect,.label div .edgeLabel{background-color:var(--md-mermaid-label-bg-color)}.edgeLabel,.edgeLabel rect{fill:var(--md-mermaid-label-bg-color);color:var(--md-mermaid-edge-color)}.edgePath .path,.flowchart-link{stroke:var(--md-mermaid-edge-color);stroke-width:.05rem}.edgePath .arrowheadPath{fill:var(--md-mermaid-edge-color);stroke:none}.cluster rect{fill:var(--md-default-fg-color--lightest);stroke:var(--md-default-fg-color--lighter)}.cluster span{color:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}g #flowchart-circleEnd,g #flowchart-circleStart,g #flowchart-crossEnd,g #flowchart-crossStart,g #flowchart-pointEnd,g #flowchart-pointStart{stroke:none}g.classGroup line,g.classGroup rect{fill:var(--md-mermaid-node-bg-color);stroke:var(--md-mermaid-node-fg-color)}g.classGroup text{fill:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}.classLabel .box{fill:var(--md-mermaid-label-bg-color);background-color:var(--md-mermaid-label-bg-color);opacity:1}.classLabel .label{fill:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}.node .divider{stroke:var(--md-mermaid-node-fg-color)}.relation{stroke:var(--md-mermaid-edge-color)}.cardinality{fill:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}.cardinality text{fill:inherit!important}defs #classDiagram-compositionEnd,defs #classDiagram-compositionStart,defs #classDiagram-dependencyEnd,defs #classDiagram-dependencyStart,defs #classDiagram-extensionEnd,defs #classDiagram-extensionStart{fill:var(--md-mermaid-edge-color)!important;stroke:var(--md-mermaid-edge-color)!important}defs #classDiagram-aggregationEnd,defs #classDiagram-aggregationStart{fill:var(--md-mermaid-label-bg-color)!important;stroke:var(--md-mermaid-edge-color)!important}g.stateGroup rect{fill:var(--md-mermaid-node-bg-color);stroke:var(--md-mermaid-node-fg-color)}g.stateGroup .state-title{fill:var(--md-mermaid-label-fg-color)!important;font-family:var(--md-mermaid-font-family)}g.stateGroup .composit{fill:var(--md-mermaid-label-bg-color)}.nodeLabel{color:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}.node circle.state-end,.node circle.state-start,.start-state{fill:var(--md-mermaid-edge-color);stroke:none}.end-state-inner,.end-state-outer{fill:var(--md-mermaid-edge-color)}.end-state-inner,.node circle.state-end{stroke:var(--md-mermaid-label-bg-color)}.transition{stroke:var(--md-mermaid-edge-color)}[id^=state-fork] rect,[id^=state-join] rect{fill:var(--md-mermaid-edge-color)!important;stroke:none!important}.statediagram-cluster.statediagram-cluster .inner{fill:var(--md-default-bg-color)}.statediagram-cluster rect{fill:var(--md-mermaid-node-bg-color);stroke:var(--md-mermaid-node-fg-color)}.statediagram-state rect.divider{fill:var(--md-default-fg-color--lightest);stroke:var(--md-default-fg-color--lighter)}defs #statediagram-barbEnd{stroke:var(--md-mermaid-edge-color)}.attributeBoxEven,.attributeBoxOdd{fill:var(--md-mermaid-node-bg-color);stroke:var(--md-mermaid-node-fg-color)}.entityBox{fill:var(--md-mermaid-label-bg-color);stroke:var(--md-mermaid-node-fg-color)}.entityLabel{fill:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}.relationshipLabelBox{fill:var(--md-mermaid-label-bg-color);fill-opacity:1;background-color:var(--md-mermaid-label-bg-color);opacity:1}.relationshipLabel{fill:var(--md-mermaid-label-fg-color)}.relationshipLine{stroke:var(--md-mermaid-edge-color)}defs #ONE_OR_MORE_END *,defs #ONE_OR_MORE_START *,defs #ONLY_ONE_END *,defs #ONLY_ONE_START *,defs #ZERO_OR_MORE_END *,defs #ZERO_OR_MORE_START *,defs #ZERO_OR_ONE_END *,defs #ZERO_OR_ONE_START *{stroke:var(--md-mermaid-edge-color)!important}defs #ZERO_OR_MORE_END circle,defs #ZERO_OR_MORE_START circle{fill:var(--md-mermaid-label-bg-color)}.actor{fill:var(--md-mermaid-sequence-actor-bg-color);stroke:var(--md-mermaid-sequence-actor-border-color)}text.actor>tspan{fill:var(--md-mermaid-sequence-actor-fg-color);font-family:var(--md-mermaid-font-family)}line{stroke:var(--md-mermaid-sequence-actor-line-color)}.actor-man circle,.actor-man line{fill:var(--md-mermaid-sequence-actorman-bg-color);stroke:var(--md-mermaid-sequence-actorman-line-color)}.messageLine0,.messageLine1{stroke:var(--md-mermaid-sequence-message-line-color)}.note{fill:var(--md-mermaid-sequence-note-bg-color);stroke:var(--md-mermaid-sequence-note-border-color)}.loopText,.loopText>tspan,.messageText,.noteText>tspan{stroke:none;font-family:var(--md-mermaid-font-family)!important}.messageText{fill:var(--md-mermaid-sequence-message-fg-color)}.loopText,.loopText>tspan{fill:var(--md-mermaid-sequence-loop-fg-color)}.noteText>tspan{fill:var(--md-mermaid-sequence-note-fg-color)}#arrowhead path{fill:var(--md-mermaid-sequence-message-line-color);stroke:none}.loopLine{fill:var(--md-mermaid-sequence-loop-bg-color);stroke:var(--md-mermaid-sequence-loop-border-color)}.labelBox{fill:var(--md-mermaid-sequence-label-bg-color);stroke:none}.labelText,.labelText>span{fill:var(--md-mermaid-sequence-label-fg-color);font-family:var(--md-mermaid-font-family)}.sequenceNumber{fill:var(--md-mermaid-sequence-number-fg-color)}rect.rect{fill:var(--md-mermaid-sequence-box-bg-color);stroke:none}rect.rect+text.text{fill:var(--md-mermaid-sequence-box-fg-color)}defs #sequencenumber{fill:var(--md-mermaid-sequence-number-bg-color)!important}";var Qr,Aa=0;function Ca(){return typeof mermaid=="undefined"||mermaid instanceof Element?gt("https://unpkg.com/mermaid@10.6.1/dist/mermaid.min.js"):R(void 0)}function _n(e){return e.classList.remove("mermaid"),Qr||(Qr=Ca().pipe(T(()=>mermaid.initialize({startOnLoad:!1,themeCSS:Ln,sequence:{actorFontSize:"16px",messageFontSize:"16px",noteFontSize:"16px"}})),m(()=>{}),Z(1))),Qr.subscribe(()=>no(this,null,function*(){e.classList.add("mermaid");let t=`__mermaid_${Aa++}`,r=S("div",{class:"mermaid"}),o=e.textContent,{svg:n,fn:i}=yield mermaid.render(t,o),s=r.attachShadow({mode:"closed"});s.innerHTML=n,e.replaceWith(r),i==null||i(s)})),Qr.pipe(m(()=>({ref:e})))}var An=S("table");function Cn(e){return e.replaceWith(An),An.replaceWith(vn(e)),R({ref:e})}function ka(e){let t=e.find(r=>r.checked)||e[0];return L(...e.map(r=>h(r,"change").pipe(m(()=>U(`label[for="${r.id}"]`))))).pipe(q(U(`label[for="${t.id}"]`)),m(r=>({active:r})))}function kn(e,{viewport$:t,target$:r}){let o=U(".tabbed-labels",e),n=W(":scope > input",e),i=zr("prev");e.append(i);let s=zr("next");return e.append(s),H(()=>{let a=new x,c=a.pipe(ee(),oe(!0));B([a,Se(e)]).pipe(j(c),Le(1,ge)).subscribe({next([{active:p},l]){let f=Ue(p),{width:u}=le(p);e.style.setProperty("--md-indicator-x",`${f.x}px`),e.style.setProperty("--md-indicator-width",`${u}px`);let d=ir(o);(f.xd.x+l.width)&&o.scrollTo({left:Math.max(0,f.x-16),behavior:"smooth"})},complete(){e.style.removeProperty("--md-indicator-x"),e.style.removeProperty("--md-indicator-width")}}),B([et(o),Se(o)]).pipe(j(c)).subscribe(([p,l])=>{let f=xt(o);i.hidden=p.x<16,s.hidden=p.x>f.width-l.width-16}),L(h(i,"click").pipe(m(()=>-1)),h(s,"click").pipe(m(()=>1))).pipe(j(c)).subscribe(p=>{let{width:l}=le(o);o.scrollBy({left:l*p,behavior:"smooth"})}),r.pipe(j(c),v(p=>n.includes(p))).subscribe(p=>p.click()),o.classList.add("tabbed-labels--linked");for(let p of n){let l=U(`label[for="${p.id}"]`);l.replaceChildren(S("a",{href:`#${l.htmlFor}`,tabIndex:-1},...Array.from(l.childNodes))),h(l.firstElementChild,"click").pipe(j(c),v(f=>!(f.metaKey||f.ctrlKey)),T(f=>{f.preventDefault(),f.stopPropagation()})).subscribe(()=>{history.replaceState({},"",`#${l.htmlFor}`),l.click()})}return G("content.tabs.link")&&a.pipe(Ee(1),ae(t)).subscribe(([{active:p},{offset:l}])=>{let f=p.innerText.trim();if(p.hasAttribute("data-md-switching"))p.removeAttribute("data-md-switching");else{let u=e.offsetTop-l.y;for(let y of W("[data-tabs]"))for(let b of W(":scope > input",y)){let D=U(`label[for="${b.id}"]`);if(D!==p&&D.innerText.trim()===f){D.setAttribute("data-md-switching",""),b.click();break}}window.scrollTo({top:e.offsetTop-u});let d=__md_get("__tabs")||[];__md_set("__tabs",[...new Set([f,...d])])}}),a.pipe(j(c)).subscribe(()=>{for(let p of W("audio, video",e))p.pause()}),ka(n).pipe(T(p=>a.next(p)),A(()=>a.complete()),m(p=>P({ref:e},p)))}).pipe(qe(ie))}function Hn(e,{viewport$:t,target$:r,print$:o}){return L(...W(".annotate:not(.highlight)",e).map(n=>wn(n,{target$:r,print$:o})),...W("pre:not(.mermaid) > code",e).map(n=>On(n,{target$:r,print$:o})),...W("pre.mermaid",e).map(n=>_n(n)),...W("table:not([class])",e).map(n=>Cn(n)),...W("details",e).map(n=>Mn(n,{target$:r,print$:o})),...W("[data-tabs]",e).map(n=>kn(n,{viewport$:t,target$:r})),...W("[title]",e).filter(()=>G("content.tooltips")).map(n=>Be(n)))}function Ha(e,{alert$:t}){return t.pipe(w(r=>L(R(!0),R(!1).pipe(Qe(2e3))).pipe(m(o=>({message:r,active:o})))))}function $n(e,t){let r=U(".md-typeset",e);return H(()=>{let o=new x;return o.subscribe(({message:n,active:i})=>{e.classList.toggle("md-dialog--active",i),r.textContent=n}),Ha(e,t).pipe(T(n=>o.next(n)),A(()=>o.complete()),m(n=>P({ref:e},n)))})}function $a({viewport$:e}){if(!G("header.autohide"))return R(!1);let t=e.pipe(m(({offset:{y:n}})=>n),Ce(2,1),m(([n,i])=>[nMath.abs(i-n.y)>100),m(([,[n]])=>n),X()),o=Ne("search");return B([e,o]).pipe(m(([{offset:n},i])=>n.y>400&&!i),X(),w(n=>n?r:R(!1)),q(!1))}function Pn(e,t){return H(()=>B([Se(e),$a(t)])).pipe(m(([{height:r},o])=>({height:r,hidden:o})),X((r,o)=>r.height===o.height&&r.hidden===o.hidden),Z(1))}function Rn(e,{header$:t,main$:r}){return H(()=>{let o=new x,n=o.pipe(ee(),oe(!0));o.pipe(te("active"),Ze(t)).subscribe(([{active:s},{hidden:a}])=>{e.classList.toggle("md-header--shadow",s&&!a),e.hidden=a});let i=fe(W("[title]",e)).pipe(v(()=>G("content.tooltips")),re(s=>Be(s)));return r.subscribe(o),t.pipe(j(n),m(s=>P({ref:e},s)),Re(i.pipe(j(n))))})}function Pa(e,{viewport$:t,header$:r}){return mr(e,{viewport$:t,header$:r}).pipe(m(({offset:{y:o}})=>{let{height:n}=le(e);return{active:o>=n}}),te("active"))}function In(e,t){return H(()=>{let r=new x;r.subscribe({next({active:n}){e.classList.toggle("md-header__title--active",n)},complete(){e.classList.remove("md-header__title--active")}});let o=ce(".md-content h1");return typeof o=="undefined"?M:Pa(o,t).pipe(T(n=>r.next(n)),A(()=>r.complete()),m(n=>P({ref:e},n)))})}function Fn(e,{viewport$:t,header$:r}){let o=r.pipe(m(({height:i})=>i),X()),n=o.pipe(w(()=>Se(e).pipe(m(({height:i})=>({top:e.offsetTop,bottom:e.offsetTop+i})),te("bottom"))));return B([o,n,t]).pipe(m(([i,{top:s,bottom:a},{offset:{y:c},size:{height:p}}])=>(p=Math.max(0,p-Math.max(0,s-c,i)-Math.max(0,p+c-a)),{offset:s-i,height:p,active:s-i<=c})),X((i,s)=>i.offset===s.offset&&i.height===s.height&&i.active===s.active))}function Ra(e){let t=__md_get("__palette")||{index:e.findIndex(r=>matchMedia(r.getAttribute("data-md-color-media")).matches)};return R(...e).pipe(re(r=>h(r,"change").pipe(m(()=>r))),q(e[Math.max(0,t.index)]),m(r=>({index:e.indexOf(r),color:{media:r.getAttribute("data-md-color-media"),scheme:r.getAttribute("data-md-color-scheme"),primary:r.getAttribute("data-md-color-primary"),accent:r.getAttribute("data-md-color-accent")}})),Z(1))}function jn(e){let t=W("input",e),r=S("meta",{name:"theme-color"});document.head.appendChild(r);let o=S("meta",{name:"color-scheme"});document.head.appendChild(o);let n=At("(prefers-color-scheme: light)");return H(()=>{let i=new x;return i.subscribe(s=>{if(document.body.setAttribute("data-md-color-switching",""),s.color.media==="(prefers-color-scheme)"){let a=matchMedia("(prefers-color-scheme: light)"),c=document.querySelector(a.matches?"[data-md-color-media='(prefers-color-scheme: light)']":"[data-md-color-media='(prefers-color-scheme: dark)']");s.color.scheme=c.getAttribute("data-md-color-scheme"),s.color.primary=c.getAttribute("data-md-color-primary"),s.color.accent=c.getAttribute("data-md-color-accent")}for(let[a,c]of Object.entries(s.color))document.body.setAttribute(`data-md-color-${a}`,c);for(let a=0;a{let s=Oe("header"),a=window.getComputedStyle(s);return o.content=a.colorScheme,a.backgroundColor.match(/\d+/g).map(c=>(+c).toString(16).padStart(2,"0")).join("")})).subscribe(s=>r.content=`#${s}`),i.pipe(Me(ie)).subscribe(()=>{document.body.removeAttribute("data-md-color-switching")}),Ra(t).pipe(j(n.pipe(Ee(1))),at(),T(s=>i.next(s)),A(()=>i.complete()),m(s=>P({ref:e},s)))})}function Wn(e,{progress$:t}){return H(()=>{let r=new x;return r.subscribe(({value:o})=>{e.style.setProperty("--md-progress-value",`${o}`)}),t.pipe(T(o=>r.next({value:o})),A(()=>r.complete()),m(o=>({ref:e,value:o})))})}var Yr=jt(Kr());function Ia(e){e.setAttribute("data-md-copying","");let t=e.closest("[data-copy]"),r=t?t.getAttribute("data-copy"):e.innerText;return e.removeAttribute("data-md-copying"),r.trimEnd()}function Un({alert$:e}){Yr.default.isSupported()&&new I(t=>{new Yr.default("[data-clipboard-target], [data-clipboard-text]",{text:r=>r.getAttribute("data-clipboard-text")||Ia(U(r.getAttribute("data-clipboard-target")))}).on("success",r=>t.next(r))}).pipe(T(t=>{t.trigger.focus()}),m(()=>we("clipboard.copied"))).subscribe(e)}function Fa(e){if(e.length<2)return[""];let[t,r]=[...e].sort((n,i)=>n.length-i.length).map(n=>n.replace(/[^/]+$/,"")),o=0;if(t===r)o=t.length;else for(;t.charCodeAt(o)===r.charCodeAt(o);)o++;return e.map(n=>n.replace(t.slice(0,o),""))}function ur(e){let t=__md_get("__sitemap",sessionStorage,e);if(t)return R(t);{let r=he();return on(new URL("sitemap.xml",e||r.base)).pipe(m(o=>Fa(W("loc",o).map(n=>n.textContent))),xe(()=>M),$e([]),T(o=>__md_set("__sitemap",o,sessionStorage,e)))}}function Nn(e){let t=ce("[rel=canonical]",e);typeof t!="undefined"&&(t.href=t.href.replace("//localhost:","//127.0.0.1:"));let r=new Map;for(let o of W(":scope > *",e)){let n=o.outerHTML;for(let i of["href","src"]){let s=o.getAttribute(i);if(s===null)continue;let a=new URL(s,t==null?void 0:t.href),c=o.cloneNode();c.setAttribute(i,`${a}`),n=c.outerHTML;break}r.set(n,o)}return r}function Dn({location$:e,viewport$:t,progress$:r}){let o=he();if(location.protocol==="file:")return M;let n=ur().pipe(m(l=>l.map(f=>`${new URL(f,o.base)}`))),i=h(document.body,"click").pipe(ae(n),w(([l,f])=>{if(!(l.target instanceof Element))return M;let u=l.target.closest("a");if(u===null)return M;if(u.target||l.metaKey||l.ctrlKey)return M;let d=new URL(u.href);return d.search=d.hash="",f.includes(`${d}`)?(l.preventDefault(),R(new URL(u.href))):M}),de());i.pipe(ue(1)).subscribe(()=>{let l=ce("link[rel=icon]");typeof l!="undefined"&&(l.href=l.href)}),h(window,"beforeunload").subscribe(()=>{history.scrollRestoration="auto"}),i.pipe(ae(t)).subscribe(([l,{offset:f}])=>{history.scrollRestoration="manual",history.replaceState(f,""),history.pushState(null,"",l)}),i.subscribe(e);let s=e.pipe(q(me()),te("pathname"),Ee(1),w(l=>lr(l,{progress$:r}).pipe(xe(()=>(st(l,!0),M))))),a=new DOMParser,c=s.pipe(w(l=>l.text()),w(l=>{let f=a.parseFromString(l,"text/html");for(let b of["[data-md-component=announce]","[data-md-component=container]","[data-md-component=header-topic]","[data-md-component=outdated]","[data-md-component=logo]","[data-md-component=skip]",...G("navigation.tabs.sticky")?["[data-md-component=tabs]"]:[]]){let D=ce(b),Q=ce(b,f);typeof D!="undefined"&&typeof Q!="undefined"&&D.replaceWith(Q)}let u=Nn(document.head),d=Nn(f.head);for(let[b,D]of d)D.getAttribute("rel")==="stylesheet"||D.hasAttribute("src")||(u.has(b)?u.delete(b):document.head.appendChild(D));for(let b of u.values())b.getAttribute("rel")==="stylesheet"||b.hasAttribute("src")||b.remove();let y=Oe("container");return We(W("script",y)).pipe(w(b=>{let D=f.createElement("script");if(b.src){for(let Q of b.getAttributeNames())D.setAttribute(Q,b.getAttribute(Q));return b.replaceWith(D),new I(Q=>{D.onload=()=>Q.complete()})}else return D.textContent=b.textContent,b.replaceWith(D),M}),ee(),oe(f))}),de());return h(window,"popstate").pipe(m(me)).subscribe(e),e.pipe(q(me()),Ce(2,1),v(([l,f])=>l.pathname===f.pathname&&l.hash!==f.hash),m(([,l])=>l)).subscribe(l=>{var f,u;history.state!==null||!l.hash?window.scrollTo(0,(u=(f=history.state)==null?void 0:f.y)!=null?u:0):(history.scrollRestoration="auto",pr(l.hash),history.scrollRestoration="manual")}),e.pipe(Ir(i),q(me()),Ce(2,1),v(([l,f])=>l.pathname===f.pathname&&l.hash===f.hash),m(([,l])=>l)).subscribe(l=>{history.scrollRestoration="auto",pr(l.hash),history.scrollRestoration="manual",history.back()}),c.pipe(ae(e)).subscribe(([,l])=>{var f,u;history.state!==null||!l.hash?window.scrollTo(0,(u=(f=history.state)==null?void 0:f.y)!=null?u:0):pr(l.hash)}),t.pipe(te("offset"),ye(100)).subscribe(({offset:l})=>{history.replaceState(l,"")}),c}var qn=jt(zn());function Kn(e){let t=e.separator.split("|").map(n=>n.replace(/(\(\?[!=<][^)]+\))/g,"").length===0?"\uFFFD":n).join("|"),r=new RegExp(t,"img"),o=(n,i,s)=>`${i}${s}`;return n=>{n=n.replace(/[\s*+\-:~^]+/g," ").trim();let i=new RegExp(`(^|${e.separator}|)(${n.replace(/[|\\{}()[\]^$+*?.-]/g,"\\$&").replace(r,"|")})`,"img");return s=>(0,qn.default)(s).replace(i,o).replace(/<\/mark>(\s+)]*>/img,"$1")}}function Ht(e){return e.type===1}function dr(e){return e.type===3}function Qn(e,t){let r=ln(e);return L(R(location.protocol!=="file:"),Ne("search")).pipe(Pe(o=>o),w(()=>t)).subscribe(({config:o,docs:n})=>r.next({type:0,data:{config:o,docs:n,options:{suggest:G("search.suggest")}}})),r}function Yn({document$:e}){let t=he(),r=De(new URL("../versions.json",t.base)).pipe(xe(()=>M)),o=r.pipe(m(n=>{let[,i]=t.base.match(/([^/]+)\/?$/);return n.find(({version:s,aliases:a})=>s===i||a.includes(i))||n[0]}));r.pipe(m(n=>new Map(n.map(i=>[`${new URL(`../${i.version}/`,t.base)}`,i]))),w(n=>h(document.body,"click").pipe(v(i=>!i.metaKey&&!i.ctrlKey),ae(o),w(([i,s])=>{if(i.target instanceof Element){let a=i.target.closest("a");if(a&&!a.target&&n.has(a.href)){let c=a.href;return!i.target.closest(".md-version")&&n.get(c)===s?M:(i.preventDefault(),R(c))}}return M}),w(i=>{let{version:s}=n.get(i);return ur(new URL(i)).pipe(m(a=>{let p=me().href.replace(t.base,"");return a.includes(p.split("#")[0])?new URL(`../${s}/${p}`,t.base):new URL(i)}))})))).subscribe(n=>st(n,!0)),B([r,o]).subscribe(([n,i])=>{U(".md-header__topic").appendChild(gn(n,i))}),e.pipe(w(()=>o)).subscribe(n=>{var s;let i=__md_get("__outdated",sessionStorage);if(i===null){i=!0;let a=((s=t.version)==null?void 0:s.default)||"latest";Array.isArray(a)||(a=[a]);e:for(let c of a)for(let p of n.aliases.concat(n.version))if(new RegExp(c,"i").test(p)){i=!1;break e}__md_set("__outdated",i,sessionStorage)}if(i)for(let a of ne("outdated"))a.hidden=!1})}function Da(e,{worker$:t}){let{searchParams:r}=me();r.has("q")&&(Ye("search",!0),e.value=r.get("q"),e.focus(),Ne("search").pipe(Pe(i=>!i)).subscribe(()=>{let i=me();i.searchParams.delete("q"),history.replaceState({},"",`${i}`)}));let o=vt(e),n=L(t.pipe(Pe(Ht)),h(e,"keyup"),o).pipe(m(()=>e.value),X());return B([n,o]).pipe(m(([i,s])=>({value:i,focus:s})),Z(1))}function Bn(e,{worker$:t}){let r=new x,o=r.pipe(ee(),oe(!0));B([t.pipe(Pe(Ht)),r],(i,s)=>s).pipe(te("value")).subscribe(({value:i})=>t.next({type:2,data:i})),r.pipe(te("focus")).subscribe(({focus:i})=>{i&&Ye("search",i)}),h(e.form,"reset").pipe(j(o)).subscribe(()=>e.focus());let n=U("header [for=__search]");return h(n,"click").subscribe(()=>e.focus()),Da(e,{worker$:t}).pipe(T(i=>r.next(i)),A(()=>r.complete()),m(i=>P({ref:e},i)),Z(1))}function Gn(e,{worker$:t,query$:r}){let o=new x,n=Go(e.parentElement).pipe(v(Boolean)),i=e.parentElement,s=U(":scope > :first-child",e),a=U(":scope > :last-child",e);Ne("search").subscribe(l=>a.setAttribute("role",l?"list":"presentation")),o.pipe(ae(r),Wr(t.pipe(Pe(Ht)))).subscribe(([{items:l},{value:f}])=>{switch(l.length){case 0:s.textContent=f.length?we("search.result.none"):we("search.result.placeholder");break;case 1:s.textContent=we("search.result.one");break;default:let u=ar(l.length);s.textContent=we("search.result.other",u)}});let c=o.pipe(T(()=>a.innerHTML=""),w(({items:l})=>L(R(...l.slice(0,10)),R(...l.slice(10)).pipe(Ce(4),Nr(n),w(([f])=>f)))),m(hn),de());return c.subscribe(l=>a.appendChild(l)),c.pipe(re(l=>{let f=ce("details",l);return typeof f=="undefined"?M:h(f,"toggle").pipe(j(o),m(()=>f))})).subscribe(l=>{l.open===!1&&l.offsetTop<=i.scrollTop&&i.scrollTo({top:l.offsetTop})}),t.pipe(v(dr),m(({data:l})=>l)).pipe(T(l=>o.next(l)),A(()=>o.complete()),m(l=>P({ref:e},l)))}function Va(e,{query$:t}){return t.pipe(m(({value:r})=>{let o=me();return o.hash="",r=r.replace(/\s+/g,"+").replace(/&/g,"%26").replace(/=/g,"%3D"),o.search=`q=${r}`,{url:o}}))}function Jn(e,t){let r=new x,o=r.pipe(ee(),oe(!0));return r.subscribe(({url:n})=>{e.setAttribute("data-clipboard-text",e.href),e.href=`${n}`}),h(e,"click").pipe(j(o)).subscribe(n=>n.preventDefault()),Va(e,t).pipe(T(n=>r.next(n)),A(()=>r.complete()),m(n=>P({ref:e},n)))}function Xn(e,{worker$:t,keyboard$:r}){let o=new x,n=Oe("search-query"),i=L(h(n,"keydown"),h(n,"focus")).pipe(Me(ie),m(()=>n.value),X());return o.pipe(Ze(i),m(([{suggest:a},c])=>{let p=c.split(/([\s-]+)/);if(a!=null&&a.length&&p[p.length-1]){let l=a[a.length-1];l.startsWith(p[p.length-1])&&(p[p.length-1]=l)}else p.length=0;return p})).subscribe(a=>e.innerHTML=a.join("").replace(/\s/g," ")),r.pipe(v(({mode:a})=>a==="search")).subscribe(a=>{switch(a.type){case"ArrowRight":e.innerText.length&&n.selectionStart===n.value.length&&(n.value=e.innerText);break}}),t.pipe(v(dr),m(({data:a})=>a)).pipe(T(a=>o.next(a)),A(()=>o.complete()),m(()=>({ref:e})))}function Zn(e,{index$:t,keyboard$:r}){let o=he();try{let n=Qn(o.search,t),i=Oe("search-query",e),s=Oe("search-result",e);h(e,"click").pipe(v(({target:c})=>c instanceof Element&&!!c.closest("a"))).subscribe(()=>Ye("search",!1)),r.pipe(v(({mode:c})=>c==="search")).subscribe(c=>{let p=Ie();switch(c.type){case"Enter":if(p===i){let l=new Map;for(let f of W(":first-child [href]",s)){let u=f.firstElementChild;l.set(f,parseFloat(u.getAttribute("data-md-score")))}if(l.size){let[[f]]=[...l].sort(([,u],[,d])=>d-u);f.click()}c.claim()}break;case"Escape":case"Tab":Ye("search",!1),i.blur();break;case"ArrowUp":case"ArrowDown":if(typeof p=="undefined")i.focus();else{let l=[i,...W(":not(details) > [href], summary, details[open] [href]",s)],f=Math.max(0,(Math.max(0,l.indexOf(p))+l.length+(c.type==="ArrowUp"?-1:1))%l.length);l[f].focus()}c.claim();break;default:i!==Ie()&&i.focus()}}),r.pipe(v(({mode:c})=>c==="global")).subscribe(c=>{switch(c.type){case"f":case"s":case"/":i.focus(),i.select(),c.claim();break}});let a=Bn(i,{worker$:n});return L(a,Gn(s,{worker$:n,query$:a})).pipe(Re(...ne("search-share",e).map(c=>Jn(c,{query$:a})),...ne("search-suggest",e).map(c=>Xn(c,{worker$:n,keyboard$:r}))))}catch(n){return e.hidden=!0,Ke}}function ei(e,{index$:t,location$:r}){return B([t,r.pipe(q(me()),v(o=>!!o.searchParams.get("h")))]).pipe(m(([o,n])=>Kn(o.config)(n.searchParams.get("h"))),m(o=>{var s;let n=new Map,i=document.createNodeIterator(e,NodeFilter.SHOW_TEXT);for(let a=i.nextNode();a;a=i.nextNode())if((s=a.parentElement)!=null&&s.offsetHeight){let c=a.textContent,p=o(c);p.length>c.length&&n.set(a,p)}for(let[a,c]of n){let{childNodes:p}=S("span",null,c);a.replaceWith(...Array.from(p))}return{ref:e,nodes:n}}))}function za(e,{viewport$:t,main$:r}){let o=e.closest(".md-grid"),n=o.offsetTop-o.parentElement.offsetTop;return B([r,t]).pipe(m(([{offset:i,height:s},{offset:{y:a}}])=>(s=s+Math.min(n,Math.max(0,a-i))-n,{height:s,locked:a>=i+n})),X((i,s)=>i.height===s.height&&i.locked===s.locked))}function Br(e,o){var n=o,{header$:t}=n,r=oo(n,["header$"]);let i=U(".md-sidebar__scrollwrap",e),{y:s}=Ue(i);return H(()=>{let a=new x,c=a.pipe(ee(),oe(!0)),p=a.pipe(Le(0,ge));return p.pipe(ae(t)).subscribe({next([{height:l},{height:f}]){i.style.height=`${l-2*s}px`,e.style.top=`${f}px`},complete(){i.style.height="",e.style.top=""}}),p.pipe(Pe()).subscribe(()=>{for(let l of W(".md-nav__link--active[href]",e)){if(!l.clientHeight)continue;let f=l.closest(".md-sidebar__scrollwrap");if(typeof f!="undefined"){let u=l.offsetTop-f.offsetTop,{height:d}=le(f);f.scrollTo({top:u-d/2})}}}),fe(W("label[tabindex]",e)).pipe(re(l=>h(l,"click").pipe(Me(ie),m(()=>l),j(c)))).subscribe(l=>{let f=U(`[id="${l.htmlFor}"]`);U(`[aria-labelledby="${l.id}"]`).setAttribute("aria-expanded",`${f.checked}`)}),za(e,r).pipe(T(l=>a.next(l)),A(()=>a.complete()),m(l=>P({ref:e},l)))})}function ti(e,t){if(typeof t!="undefined"){let r=`https://api.github.com/repos/${e}/${t}`;return Lt(De(`${r}/releases/latest`).pipe(xe(()=>M),m(o=>({version:o.tag_name})),$e({})),De(r).pipe(xe(()=>M),m(o=>({stars:o.stargazers_count,forks:o.forks_count})),$e({}))).pipe(m(([o,n])=>P(P({},o),n)))}else{let r=`https://api.github.com/users/${e}`;return De(r).pipe(m(o=>({repositories:o.public_repos})),$e({}))}}function ri(e,t){let r=`https://${e}/api/v4/projects/${encodeURIComponent(t)}`;return De(r).pipe(xe(()=>M),m(({star_count:o,forks_count:n})=>({stars:o,forks:n})),$e({}))}function oi(e){let t=e.match(/^.+github\.com\/([^/]+)\/?([^/]+)?/i);if(t){let[,r,o]=t;return ti(r,o)}if(t=e.match(/^.+?([^/]*gitlab[^/]+)\/(.+?)\/?$/i),t){let[,r,o]=t;return ri(r,o)}return M}var qa;function Ka(e){return qa||(qa=H(()=>{let t=__md_get("__source",sessionStorage);if(t)return R(t);if(ne("consent").length){let o=__md_get("__consent");if(!(o&&o.github))return M}return oi(e.href).pipe(T(o=>__md_set("__source",o,sessionStorage)))}).pipe(xe(()=>M),v(t=>Object.keys(t).length>0),m(t=>({facts:t})),Z(1)))}function ni(e){let t=U(":scope > :last-child",e);return H(()=>{let r=new x;return r.subscribe(({facts:o})=>{t.appendChild(bn(o)),t.classList.add("md-source__repository--active")}),Ka(e).pipe(T(o=>r.next(o)),A(()=>r.complete()),m(o=>P({ref:e},o)))})}function Qa(e,{viewport$:t,header$:r}){return Se(document.body).pipe(w(()=>mr(e,{header$:r,viewport$:t})),m(({offset:{y:o}})=>({hidden:o>=10})),te("hidden"))}function ii(e,t){return H(()=>{let r=new x;return r.subscribe({next({hidden:o}){e.hidden=o},complete(){e.hidden=!1}}),(G("navigation.tabs.sticky")?R({hidden:!1}):Qa(e,t)).pipe(T(o=>r.next(o)),A(()=>r.complete()),m(o=>P({ref:e},o)))})}function Ya(e,{viewport$:t,header$:r}){let o=new Map,n=W("[href^=\\#]",e);for(let a of n){let c=decodeURIComponent(a.hash.substring(1)),p=ce(`[id="${c}"]`);typeof p!="undefined"&&o.set(a,p)}let i=r.pipe(te("height"),m(({height:a})=>{let c=Oe("main"),p=U(":scope > :first-child",c);return a+.8*(p.offsetTop-c.offsetTop)}),de());return Se(document.body).pipe(te("height"),w(a=>H(()=>{let c=[];return R([...o].reduce((p,[l,f])=>{for(;c.length&&o.get(c[c.length-1]).tagName>=f.tagName;)c.pop();let u=f.offsetTop;for(;!u&&f.parentElement;)f=f.parentElement,u=f.offsetTop;let d=f.offsetParent;for(;d;d=d.offsetParent)u+=d.offsetTop;return p.set([...c=[...c,l]].reverse(),u)},new Map))}).pipe(m(c=>new Map([...c].sort(([,p],[,l])=>p-l))),Ze(i),w(([c,p])=>t.pipe(Fr(([l,f],{offset:{y:u},size:d})=>{let y=u+d.height>=Math.floor(a.height);for(;f.length;){let[,b]=f[0];if(b-p=u&&!y)f=[l.pop(),...f];else break}return[l,f]},[[],[...c]]),X((l,f)=>l[0]===f[0]&&l[1]===f[1])))))).pipe(m(([a,c])=>({prev:a.map(([p])=>p),next:c.map(([p])=>p)})),q({prev:[],next:[]}),Ce(2,1),m(([a,c])=>a.prev.length{let i=new x,s=i.pipe(ee(),oe(!0));if(i.subscribe(({prev:a,next:c})=>{for(let[p]of c)p.classList.remove("md-nav__link--passed"),p.classList.remove("md-nav__link--active");for(let[p,[l]]of a.entries())l.classList.add("md-nav__link--passed"),l.classList.toggle("md-nav__link--active",p===a.length-1)}),G("toc.follow")){let a=L(t.pipe(ye(1),m(()=>{})),t.pipe(ye(250),m(()=>"smooth")));i.pipe(v(({prev:c})=>c.length>0),Ze(o.pipe(Me(ie))),ae(a)).subscribe(([[{prev:c}],p])=>{let[l]=c[c.length-1];if(l.offsetHeight){let f=sr(l);if(typeof f!="undefined"){let u=l.offsetTop-f.offsetTop,{height:d}=le(f);f.scrollTo({top:u-d/2,behavior:p})}}})}return G("navigation.tracking")&&t.pipe(j(s),te("offset"),ye(250),Ee(1),j(n.pipe(Ee(1))),at({delay:250}),ae(i)).subscribe(([,{prev:a}])=>{let c=me(),p=a[a.length-1];if(p&&p.length){let[l]=p,{hash:f}=new URL(l.href);c.hash!==f&&(c.hash=f,history.replaceState({},"",`${c}`))}else c.hash="",history.replaceState({},"",`${c}`)}),Ya(e,{viewport$:t,header$:r}).pipe(T(a=>i.next(a)),A(()=>i.complete()),m(a=>P({ref:e},a)))})}function Ba(e,{viewport$:t,main$:r,target$:o}){let n=t.pipe(m(({offset:{y:s}})=>s),Ce(2,1),m(([s,a])=>s>a&&a>0),X()),i=r.pipe(m(({active:s})=>s));return B([i,n]).pipe(m(([s,a])=>!(s&&a)),X(),j(o.pipe(Ee(1))),oe(!0),at({delay:250}),m(s=>({hidden:s})))}function si(e,{viewport$:t,header$:r,main$:o,target$:n}){let i=new x,s=i.pipe(ee(),oe(!0));return i.subscribe({next({hidden:a}){e.hidden=a,a?(e.setAttribute("tabindex","-1"),e.blur()):e.removeAttribute("tabindex")},complete(){e.style.top="",e.hidden=!0,e.removeAttribute("tabindex")}}),r.pipe(j(s),te("height")).subscribe(({height:a})=>{e.style.top=`${a+16}px`}),h(e,"click").subscribe(a=>{a.preventDefault(),window.scrollTo({top:0})}),Ba(e,{viewport$:t,main$:o,target$:n}).pipe(T(a=>i.next(a)),A(()=>i.complete()),m(a=>P({ref:e},a)))}function ci({document$:e}){e.pipe(w(()=>W(".md-ellipsis")),re(t=>yt(t).pipe(j(e.pipe(Ee(1))),v(r=>r),m(()=>t),ue(1))),v(t=>t.offsetWidth{let r=t.innerText,o=t.closest("a")||t;return o.title=r,Be(o).pipe(j(e.pipe(Ee(1))),A(()=>o.removeAttribute("title")))})).subscribe(),e.pipe(w(()=>W(".md-status")),re(t=>Be(t))).subscribe()}function pi({document$:e,tablet$:t}){e.pipe(w(()=>W(".md-toggle--indeterminate")),T(r=>{r.indeterminate=!0,r.checked=!1}),re(r=>h(r,"change").pipe(Ur(()=>r.classList.contains("md-toggle--indeterminate")),m(()=>r))),ae(t)).subscribe(([r,o])=>{r.classList.remove("md-toggle--indeterminate"),o&&(r.checked=!1)})}function Ga(){return/(iPad|iPhone|iPod)/.test(navigator.userAgent)}function li({document$:e}){e.pipe(w(()=>W("[data-md-scrollfix]")),T(t=>t.removeAttribute("data-md-scrollfix")),v(Ga),re(t=>h(t,"touchstart").pipe(m(()=>t)))).subscribe(t=>{let r=t.scrollTop;r===0?t.scrollTop=1:r+t.offsetHeight===t.scrollHeight&&(t.scrollTop=r-1)})}function mi({viewport$:e,tablet$:t}){B([Ne("search"),t]).pipe(m(([r,o])=>r&&!o),w(r=>R(r).pipe(Qe(r?400:100))),ae(e)).subscribe(([r,{offset:{y:o}}])=>{if(r)document.body.setAttribute("data-md-scrolllock",""),document.body.style.top=`-${o}px`;else{let n=-1*parseInt(document.body.style.top,10);document.body.removeAttribute("data-md-scrolllock"),document.body.style.top="",n&&window.scrollTo(0,n)}})}Object.entries||(Object.entries=function(e){let t=[];for(let r of Object.keys(e))t.push([r,e[r]]);return t});Object.values||(Object.values=function(e){let t=[];for(let r of Object.keys(e))t.push(e[r]);return t});typeof Element!="undefined"&&(Element.prototype.scrollTo||(Element.prototype.scrollTo=function(e,t){typeof e=="object"?(this.scrollLeft=e.left,this.scrollTop=e.top):(this.scrollLeft=e,this.scrollTop=t)}),Element.prototype.replaceWith||(Element.prototype.replaceWith=function(...e){let t=this.parentNode;if(t){e.length===0&&t.removeChild(this);for(let r=e.length-1;r>=0;r--){let o=e[r];typeof o=="string"?o=document.createTextNode(o):o.parentNode&&o.parentNode.removeChild(o),r?t.insertBefore(this.previousSibling,o):t.replaceChild(o,this)}}}));function Ja(){return location.protocol==="file:"?gt(`${new URL("search/search_index.js",Gr.base)}`).pipe(m(()=>__index),Z(1)):De(new URL("search/search_index.json",Gr.base))}document.documentElement.classList.remove("no-js");document.documentElement.classList.add("js");var rt=zo(),Pt=Zo(),wt=tn(Pt),Jr=Xo(),_e=pn(),hr=At("(min-width: 960px)"),ui=At("(min-width: 1220px)"),di=rn(),Gr=he(),hi=document.forms.namedItem("search")?Ja():Ke,Xr=new x;Un({alert$:Xr});var Zr=new x;G("navigation.instant")&&Dn({location$:Pt,viewport$:_e,progress$:Zr}).subscribe(rt);var fi;((fi=Gr.version)==null?void 0:fi.provider)==="mike"&&Yn({document$:rt});L(Pt,wt).pipe(Qe(125)).subscribe(()=>{Ye("drawer",!1),Ye("search",!1)});Jr.pipe(v(({mode:e})=>e==="global")).subscribe(e=>{switch(e.type){case"p":case",":let t=ce("link[rel=prev]");typeof t!="undefined"&&st(t);break;case"n":case".":let r=ce("link[rel=next]");typeof r!="undefined"&&st(r);break;case"Enter":let o=Ie();o instanceof HTMLLabelElement&&o.click()}});ci({document$:rt});pi({document$:rt,tablet$:hr});li({document$:rt});mi({viewport$:_e,tablet$:hr});var tt=Pn(Oe("header"),{viewport$:_e}),$t=rt.pipe(m(()=>Oe("main")),w(e=>Fn(e,{viewport$:_e,header$:tt})),Z(1)),Xa=L(...ne("consent").map(e=>fn(e,{target$:wt})),...ne("dialog").map(e=>$n(e,{alert$:Xr})),...ne("header").map(e=>Rn(e,{viewport$:_e,header$:tt,main$:$t})),...ne("palette").map(e=>jn(e)),...ne("progress").map(e=>Wn(e,{progress$:Zr})),...ne("search").map(e=>Zn(e,{index$:hi,keyboard$:Jr})),...ne("source").map(e=>ni(e))),Za=H(()=>L(...ne("announce").map(e=>mn(e)),...ne("content").map(e=>Hn(e,{viewport$:_e,target$:wt,print$:di})),...ne("content").map(e=>G("search.highlight")?ei(e,{index$:hi,location$:Pt}):M),...ne("header-title").map(e=>In(e,{viewport$:_e,header$:tt})),...ne("sidebar").map(e=>e.getAttribute("data-md-type")==="navigation"?Dr(ui,()=>Br(e,{viewport$:_e,header$:tt,main$:$t})):Dr(hr,()=>Br(e,{viewport$:_e,header$:tt,main$:$t}))),...ne("tabs").map(e=>ii(e,{viewport$:_e,header$:tt})),...ne("toc").map(e=>ai(e,{viewport$:_e,header$:tt,main$:$t,target$:wt})),...ne("top").map(e=>si(e,{viewport$:_e,header$:tt,main$:$t,target$:wt})))),bi=rt.pipe(w(()=>Za),Re(Xa),Z(1));bi.subscribe();window.document$=rt;window.location$=Pt;window.target$=wt;window.keyboard$=Jr;window.viewport$=_e;window.tablet$=hr;window.screen$=ui;window.print$=di;window.alert$=Xr;window.progress$=Zr;window.component$=bi;})(); +//# sourceMappingURL=bundle.d7c377c4.min.js.map + diff --git a/assets/javascripts/bundle.d7c377c4.min.js.map b/assets/javascripts/bundle.d7c377c4.min.js.map new file mode 100644 index 0000000..a57d388 --- /dev/null +++ b/assets/javascripts/bundle.d7c377c4.min.js.map @@ -0,0 +1,7 @@ +{ + "version": 3, + "sources": ["node_modules/focus-visible/dist/focus-visible.js", "node_modules/clipboard/dist/clipboard.js", "node_modules/escape-html/index.js", "src/templates/assets/javascripts/bundle.ts", "node_modules/rxjs/node_modules/tslib/tslib.es6.js", "node_modules/rxjs/src/internal/util/isFunction.ts", "node_modules/rxjs/src/internal/util/createErrorClass.ts", "node_modules/rxjs/src/internal/util/UnsubscriptionError.ts", "node_modules/rxjs/src/internal/util/arrRemove.ts", "node_modules/rxjs/src/internal/Subscription.ts", "node_modules/rxjs/src/internal/config.ts", "node_modules/rxjs/src/internal/scheduler/timeoutProvider.ts", "node_modules/rxjs/src/internal/util/reportUnhandledError.ts", "node_modules/rxjs/src/internal/util/noop.ts", "node_modules/rxjs/src/internal/NotificationFactories.ts", "node_modules/rxjs/src/internal/util/errorContext.ts", "node_modules/rxjs/src/internal/Subscriber.ts", "node_modules/rxjs/src/internal/symbol/observable.ts", "node_modules/rxjs/src/internal/util/identity.ts", "node_modules/rxjs/src/internal/util/pipe.ts", "node_modules/rxjs/src/internal/Observable.ts", "node_modules/rxjs/src/internal/util/lift.ts", "node_modules/rxjs/src/internal/operators/OperatorSubscriber.ts", "node_modules/rxjs/src/internal/scheduler/animationFrameProvider.ts", "node_modules/rxjs/src/internal/util/ObjectUnsubscribedError.ts", "node_modules/rxjs/src/internal/Subject.ts", "node_modules/rxjs/src/internal/scheduler/dateTimestampProvider.ts", "node_modules/rxjs/src/internal/ReplaySubject.ts", "node_modules/rxjs/src/internal/scheduler/Action.ts", "node_modules/rxjs/src/internal/scheduler/intervalProvider.ts", "node_modules/rxjs/src/internal/scheduler/AsyncAction.ts", "node_modules/rxjs/src/internal/Scheduler.ts", "node_modules/rxjs/src/internal/scheduler/AsyncScheduler.ts", "node_modules/rxjs/src/internal/scheduler/async.ts", "node_modules/rxjs/src/internal/scheduler/AnimationFrameAction.ts", "node_modules/rxjs/src/internal/scheduler/AnimationFrameScheduler.ts", "node_modules/rxjs/src/internal/scheduler/animationFrame.ts", "node_modules/rxjs/src/internal/observable/empty.ts", "node_modules/rxjs/src/internal/util/isScheduler.ts", "node_modules/rxjs/src/internal/util/args.ts", "node_modules/rxjs/src/internal/util/isArrayLike.ts", "node_modules/rxjs/src/internal/util/isPromise.ts", "node_modules/rxjs/src/internal/util/isInteropObservable.ts", "node_modules/rxjs/src/internal/util/isAsyncIterable.ts", "node_modules/rxjs/src/internal/util/throwUnobservableError.ts", "node_modules/rxjs/src/internal/symbol/iterator.ts", "node_modules/rxjs/src/internal/util/isIterable.ts", "node_modules/rxjs/src/internal/util/isReadableStreamLike.ts", "node_modules/rxjs/src/internal/observable/innerFrom.ts", "node_modules/rxjs/src/internal/util/executeSchedule.ts", "node_modules/rxjs/src/internal/operators/observeOn.ts", "node_modules/rxjs/src/internal/operators/subscribeOn.ts", "node_modules/rxjs/src/internal/scheduled/scheduleObservable.ts", "node_modules/rxjs/src/internal/scheduled/schedulePromise.ts", "node_modules/rxjs/src/internal/scheduled/scheduleArray.ts", "node_modules/rxjs/src/internal/scheduled/scheduleIterable.ts", "node_modules/rxjs/src/internal/scheduled/scheduleAsyncIterable.ts", "node_modules/rxjs/src/internal/scheduled/scheduleReadableStreamLike.ts", "node_modules/rxjs/src/internal/scheduled/scheduled.ts", "node_modules/rxjs/src/internal/observable/from.ts", "node_modules/rxjs/src/internal/observable/of.ts", "node_modules/rxjs/src/internal/observable/throwError.ts", "node_modules/rxjs/src/internal/util/EmptyError.ts", "node_modules/rxjs/src/internal/util/isDate.ts", "node_modules/rxjs/src/internal/operators/map.ts", "node_modules/rxjs/src/internal/util/mapOneOrManyArgs.ts", "node_modules/rxjs/src/internal/util/argsArgArrayOrObject.ts", "node_modules/rxjs/src/internal/util/createObject.ts", "node_modules/rxjs/src/internal/observable/combineLatest.ts", "node_modules/rxjs/src/internal/operators/mergeInternals.ts", "node_modules/rxjs/src/internal/operators/mergeMap.ts", "node_modules/rxjs/src/internal/operators/mergeAll.ts", "node_modules/rxjs/src/internal/operators/concatAll.ts", "node_modules/rxjs/src/internal/observable/concat.ts", "node_modules/rxjs/src/internal/observable/defer.ts", "node_modules/rxjs/src/internal/observable/fromEvent.ts", "node_modules/rxjs/src/internal/observable/fromEventPattern.ts", "node_modules/rxjs/src/internal/observable/timer.ts", "node_modules/rxjs/src/internal/observable/merge.ts", "node_modules/rxjs/src/internal/observable/never.ts", "node_modules/rxjs/src/internal/util/argsOrArgArray.ts", "node_modules/rxjs/src/internal/operators/filter.ts", "node_modules/rxjs/src/internal/observable/zip.ts", "node_modules/rxjs/src/internal/operators/audit.ts", "node_modules/rxjs/src/internal/operators/auditTime.ts", "node_modules/rxjs/src/internal/operators/bufferCount.ts", "node_modules/rxjs/src/internal/operators/catchError.ts", "node_modules/rxjs/src/internal/operators/scanInternals.ts", "node_modules/rxjs/src/internal/operators/combineLatest.ts", "node_modules/rxjs/src/internal/operators/combineLatestWith.ts", "node_modules/rxjs/src/internal/operators/debounceTime.ts", "node_modules/rxjs/src/internal/operators/defaultIfEmpty.ts", "node_modules/rxjs/src/internal/operators/take.ts", "node_modules/rxjs/src/internal/operators/ignoreElements.ts", "node_modules/rxjs/src/internal/operators/mapTo.ts", "node_modules/rxjs/src/internal/operators/delayWhen.ts", "node_modules/rxjs/src/internal/operators/delay.ts", "node_modules/rxjs/src/internal/operators/distinctUntilChanged.ts", "node_modules/rxjs/src/internal/operators/distinctUntilKeyChanged.ts", "node_modules/rxjs/src/internal/operators/throwIfEmpty.ts", "node_modules/rxjs/src/internal/operators/endWith.ts", "node_modules/rxjs/src/internal/operators/finalize.ts", "node_modules/rxjs/src/internal/operators/first.ts", "node_modules/rxjs/src/internal/operators/takeLast.ts", "node_modules/rxjs/src/internal/operators/merge.ts", "node_modules/rxjs/src/internal/operators/mergeWith.ts", "node_modules/rxjs/src/internal/operators/repeat.ts", "node_modules/rxjs/src/internal/operators/sample.ts", "node_modules/rxjs/src/internal/operators/scan.ts", "node_modules/rxjs/src/internal/operators/share.ts", "node_modules/rxjs/src/internal/operators/shareReplay.ts", "node_modules/rxjs/src/internal/operators/skip.ts", "node_modules/rxjs/src/internal/operators/skipUntil.ts", "node_modules/rxjs/src/internal/operators/startWith.ts", "node_modules/rxjs/src/internal/operators/switchMap.ts", "node_modules/rxjs/src/internal/operators/takeUntil.ts", "node_modules/rxjs/src/internal/operators/takeWhile.ts", "node_modules/rxjs/src/internal/operators/tap.ts", "node_modules/rxjs/src/internal/operators/throttle.ts", "node_modules/rxjs/src/internal/operators/throttleTime.ts", "node_modules/rxjs/src/internal/operators/withLatestFrom.ts", "node_modules/rxjs/src/internal/operators/zip.ts", "node_modules/rxjs/src/internal/operators/zipWith.ts", "src/templates/assets/javascripts/browser/document/index.ts", "src/templates/assets/javascripts/browser/element/_/index.ts", "src/templates/assets/javascripts/browser/element/focus/index.ts", "src/templates/assets/javascripts/browser/element/hover/index.ts", "src/templates/assets/javascripts/browser/element/offset/_/index.ts", "src/templates/assets/javascripts/browser/element/offset/content/index.ts", "src/templates/assets/javascripts/utilities/h/index.ts", "src/templates/assets/javascripts/utilities/round/index.ts", "src/templates/assets/javascripts/browser/script/index.ts", "src/templates/assets/javascripts/browser/element/size/_/index.ts", "src/templates/assets/javascripts/browser/element/size/content/index.ts", "src/templates/assets/javascripts/browser/element/visibility/index.ts", "src/templates/assets/javascripts/browser/toggle/index.ts", "src/templates/assets/javascripts/browser/keyboard/index.ts", "src/templates/assets/javascripts/browser/location/_/index.ts", "src/templates/assets/javascripts/browser/location/hash/index.ts", "src/templates/assets/javascripts/browser/media/index.ts", "src/templates/assets/javascripts/browser/request/index.ts", "src/templates/assets/javascripts/browser/viewport/offset/index.ts", "src/templates/assets/javascripts/browser/viewport/size/index.ts", "src/templates/assets/javascripts/browser/viewport/_/index.ts", "src/templates/assets/javascripts/browser/viewport/at/index.ts", "src/templates/assets/javascripts/browser/worker/index.ts", "src/templates/assets/javascripts/_/index.ts", "src/templates/assets/javascripts/components/_/index.ts", "src/templates/assets/javascripts/components/announce/index.ts", "src/templates/assets/javascripts/components/consent/index.ts", "src/templates/assets/javascripts/templates/tooltip/index.tsx", "src/templates/assets/javascripts/templates/annotation/index.tsx", "src/templates/assets/javascripts/templates/clipboard/index.tsx", "src/templates/assets/javascripts/templates/search/index.tsx", "src/templates/assets/javascripts/templates/source/index.tsx", "src/templates/assets/javascripts/templates/tabbed/index.tsx", "src/templates/assets/javascripts/templates/table/index.tsx", "src/templates/assets/javascripts/templates/version/index.tsx", "src/templates/assets/javascripts/components/tooltip/index.ts", "src/templates/assets/javascripts/components/content/annotation/_/index.ts", "src/templates/assets/javascripts/components/content/annotation/list/index.ts", "src/templates/assets/javascripts/components/content/annotation/block/index.ts", "src/templates/assets/javascripts/components/content/code/_/index.ts", "src/templates/assets/javascripts/components/content/details/index.ts", "src/templates/assets/javascripts/components/content/mermaid/index.css", "src/templates/assets/javascripts/components/content/mermaid/index.ts", "src/templates/assets/javascripts/components/content/table/index.ts", "src/templates/assets/javascripts/components/content/tabs/index.ts", "src/templates/assets/javascripts/components/content/_/index.ts", "src/templates/assets/javascripts/components/dialog/index.ts", "src/templates/assets/javascripts/components/header/_/index.ts", "src/templates/assets/javascripts/components/header/title/index.ts", "src/templates/assets/javascripts/components/main/index.ts", "src/templates/assets/javascripts/components/palette/index.ts", "src/templates/assets/javascripts/components/progress/index.ts", "src/templates/assets/javascripts/integrations/clipboard/index.ts", "src/templates/assets/javascripts/integrations/sitemap/index.ts", "src/templates/assets/javascripts/integrations/instant/index.ts", "src/templates/assets/javascripts/integrations/search/highlighter/index.ts", "src/templates/assets/javascripts/integrations/search/worker/message/index.ts", "src/templates/assets/javascripts/integrations/search/worker/_/index.ts", "src/templates/assets/javascripts/integrations/version/index.ts", "src/templates/assets/javascripts/components/search/query/index.ts", "src/templates/assets/javascripts/components/search/result/index.ts", "src/templates/assets/javascripts/components/search/share/index.ts", "src/templates/assets/javascripts/components/search/suggest/index.ts", "src/templates/assets/javascripts/components/search/_/index.ts", "src/templates/assets/javascripts/components/search/highlight/index.ts", "src/templates/assets/javascripts/components/sidebar/index.ts", "src/templates/assets/javascripts/components/source/facts/github/index.ts", "src/templates/assets/javascripts/components/source/facts/gitlab/index.ts", "src/templates/assets/javascripts/components/source/facts/_/index.ts", "src/templates/assets/javascripts/components/source/_/index.ts", "src/templates/assets/javascripts/components/tabs/index.ts", "src/templates/assets/javascripts/components/toc/index.ts", "src/templates/assets/javascripts/components/top/index.ts", "src/templates/assets/javascripts/patches/ellipsis/index.ts", "src/templates/assets/javascripts/patches/indeterminate/index.ts", "src/templates/assets/javascripts/patches/scrollfix/index.ts", "src/templates/assets/javascripts/patches/scrolllock/index.ts", "src/templates/assets/javascripts/polyfills/index.ts"], + "sourcesContent": ["(function (global, factory) {\n typeof exports === 'object' && typeof module !== 'undefined' ? factory() :\n typeof define === 'function' && define.amd ? define(factory) :\n (factory());\n}(this, (function () { 'use strict';\n\n /**\n * Applies the :focus-visible polyfill at the given scope.\n * A scope in this case is either the top-level Document or a Shadow Root.\n *\n * @param {(Document|ShadowRoot)} scope\n * @see https://github.com/WICG/focus-visible\n */\n function applyFocusVisiblePolyfill(scope) {\n var hadKeyboardEvent = true;\n var hadFocusVisibleRecently = false;\n var hadFocusVisibleRecentlyTimeout = null;\n\n var inputTypesAllowlist = {\n text: true,\n search: true,\n url: true,\n tel: true,\n email: true,\n password: true,\n number: true,\n date: true,\n month: true,\n week: true,\n time: true,\n datetime: true,\n 'datetime-local': true\n };\n\n /**\n * Helper function for legacy browsers and iframes which sometimes focus\n * elements like document, body, and non-interactive SVG.\n * @param {Element} el\n */\n function isValidFocusTarget(el) {\n if (\n el &&\n el !== document &&\n el.nodeName !== 'HTML' &&\n el.nodeName !== 'BODY' &&\n 'classList' in el &&\n 'contains' in el.classList\n ) {\n return true;\n }\n return false;\n }\n\n /**\n * Computes whether the given element should automatically trigger the\n * `focus-visible` class being added, i.e. whether it should always match\n * `:focus-visible` when focused.\n * @param {Element} el\n * @return {boolean}\n */\n function focusTriggersKeyboardModality(el) {\n var type = el.type;\n var tagName = el.tagName;\n\n if (tagName === 'INPUT' && inputTypesAllowlist[type] && !el.readOnly) {\n return true;\n }\n\n if (tagName === 'TEXTAREA' && !el.readOnly) {\n return true;\n }\n\n if (el.isContentEditable) {\n return true;\n }\n\n return false;\n }\n\n /**\n * Add the `focus-visible` class to the given element if it was not added by\n * the author.\n * @param {Element} el\n */\n function addFocusVisibleClass(el) {\n if (el.classList.contains('focus-visible')) {\n return;\n }\n el.classList.add('focus-visible');\n el.setAttribute('data-focus-visible-added', '');\n }\n\n /**\n * Remove the `focus-visible` class from the given element if it was not\n * originally added by the author.\n * @param {Element} el\n */\n function removeFocusVisibleClass(el) {\n if (!el.hasAttribute('data-focus-visible-added')) {\n return;\n }\n el.classList.remove('focus-visible');\n el.removeAttribute('data-focus-visible-added');\n }\n\n /**\n * If the most recent user interaction was via the keyboard;\n * and the key press did not include a meta, alt/option, or control key;\n * then the modality is keyboard. Otherwise, the modality is not keyboard.\n * Apply `focus-visible` to any current active element and keep track\n * of our keyboard modality state with `hadKeyboardEvent`.\n * @param {KeyboardEvent} e\n */\n function onKeyDown(e) {\n if (e.metaKey || e.altKey || e.ctrlKey) {\n return;\n }\n\n if (isValidFocusTarget(scope.activeElement)) {\n addFocusVisibleClass(scope.activeElement);\n }\n\n hadKeyboardEvent = true;\n }\n\n /**\n * If at any point a user clicks with a pointing device, ensure that we change\n * the modality away from keyboard.\n * This avoids the situation where a user presses a key on an already focused\n * element, and then clicks on a different element, focusing it with a\n * pointing device, while we still think we're in keyboard modality.\n * @param {Event} e\n */\n function onPointerDown(e) {\n hadKeyboardEvent = false;\n }\n\n /**\n * On `focus`, add the `focus-visible` class to the target if:\n * - the target received focus as a result of keyboard navigation, or\n * - the event target is an element that will likely require interaction\n * via the keyboard (e.g. a text box)\n * @param {Event} e\n */\n function onFocus(e) {\n // Prevent IE from focusing the document or HTML element.\n if (!isValidFocusTarget(e.target)) {\n return;\n }\n\n if (hadKeyboardEvent || focusTriggersKeyboardModality(e.target)) {\n addFocusVisibleClass(e.target);\n }\n }\n\n /**\n * On `blur`, remove the `focus-visible` class from the target.\n * @param {Event} e\n */\n function onBlur(e) {\n if (!isValidFocusTarget(e.target)) {\n return;\n }\n\n if (\n e.target.classList.contains('focus-visible') ||\n e.target.hasAttribute('data-focus-visible-added')\n ) {\n // To detect a tab/window switch, we look for a blur event followed\n // rapidly by a visibility change.\n // If we don't see a visibility change within 100ms, it's probably a\n // regular focus change.\n hadFocusVisibleRecently = true;\n window.clearTimeout(hadFocusVisibleRecentlyTimeout);\n hadFocusVisibleRecentlyTimeout = window.setTimeout(function() {\n hadFocusVisibleRecently = false;\n }, 100);\n removeFocusVisibleClass(e.target);\n }\n }\n\n /**\n * If the user changes tabs, keep track of whether or not the previously\n * focused element had .focus-visible.\n * @param {Event} e\n */\n function onVisibilityChange(e) {\n if (document.visibilityState === 'hidden') {\n // If the tab becomes active again, the browser will handle calling focus\n // on the element (Safari actually calls it twice).\n // If this tab change caused a blur on an element with focus-visible,\n // re-apply the class when the user switches back to the tab.\n if (hadFocusVisibleRecently) {\n hadKeyboardEvent = true;\n }\n addInitialPointerMoveListeners();\n }\n }\n\n /**\n * Add a group of listeners to detect usage of any pointing devices.\n * These listeners will be added when the polyfill first loads, and anytime\n * the window is blurred, so that they are active when the window regains\n * focus.\n */\n function addInitialPointerMoveListeners() {\n document.addEventListener('mousemove', onInitialPointerMove);\n document.addEventListener('mousedown', onInitialPointerMove);\n document.addEventListener('mouseup', onInitialPointerMove);\n document.addEventListener('pointermove', onInitialPointerMove);\n document.addEventListener('pointerdown', onInitialPointerMove);\n document.addEventListener('pointerup', onInitialPointerMove);\n document.addEventListener('touchmove', onInitialPointerMove);\n document.addEventListener('touchstart', onInitialPointerMove);\n document.addEventListener('touchend', onInitialPointerMove);\n }\n\n function removeInitialPointerMoveListeners() {\n document.removeEventListener('mousemove', onInitialPointerMove);\n document.removeEventListener('mousedown', onInitialPointerMove);\n document.removeEventListener('mouseup', onInitialPointerMove);\n document.removeEventListener('pointermove', onInitialPointerMove);\n document.removeEventListener('pointerdown', onInitialPointerMove);\n document.removeEventListener('pointerup', onInitialPointerMove);\n document.removeEventListener('touchmove', onInitialPointerMove);\n document.removeEventListener('touchstart', onInitialPointerMove);\n document.removeEventListener('touchend', onInitialPointerMove);\n }\n\n /**\n * When the polfyill first loads, assume the user is in keyboard modality.\n * If any event is received from a pointing device (e.g. mouse, pointer,\n * touch), turn off keyboard modality.\n * This accounts for situations where focus enters the page from the URL bar.\n * @param {Event} e\n */\n function onInitialPointerMove(e) {\n // Work around a Safari quirk that fires a mousemove on whenever the\n // window blurs, even if you're tabbing out of the page. \u00AF\\_(\u30C4)_/\u00AF\n if (e.target.nodeName && e.target.nodeName.toLowerCase() === 'html') {\n return;\n }\n\n hadKeyboardEvent = false;\n removeInitialPointerMoveListeners();\n }\n\n // For some kinds of state, we are interested in changes at the global scope\n // only. For example, global pointer input, global key presses and global\n // visibility change should affect the state at every scope:\n document.addEventListener('keydown', onKeyDown, true);\n document.addEventListener('mousedown', onPointerDown, true);\n document.addEventListener('pointerdown', onPointerDown, true);\n document.addEventListener('touchstart', onPointerDown, true);\n document.addEventListener('visibilitychange', onVisibilityChange, true);\n\n addInitialPointerMoveListeners();\n\n // For focus and blur, we specifically care about state changes in the local\n // scope. This is because focus / blur events that originate from within a\n // shadow root are not re-dispatched from the host element if it was already\n // the active element in its own scope:\n scope.addEventListener('focus', onFocus, true);\n scope.addEventListener('blur', onBlur, true);\n\n // We detect that a node is a ShadowRoot by ensuring that it is a\n // DocumentFragment and also has a host property. This check covers native\n // implementation and polyfill implementation transparently. If we only cared\n // about the native implementation, we could just check if the scope was\n // an instance of a ShadowRoot.\n if (scope.nodeType === Node.DOCUMENT_FRAGMENT_NODE && scope.host) {\n // Since a ShadowRoot is a special kind of DocumentFragment, it does not\n // have a root element to add a class to. So, we add this attribute to the\n // host element instead:\n scope.host.setAttribute('data-js-focus-visible', '');\n } else if (scope.nodeType === Node.DOCUMENT_NODE) {\n document.documentElement.classList.add('js-focus-visible');\n document.documentElement.setAttribute('data-js-focus-visible', '');\n }\n }\n\n // It is important to wrap all references to global window and document in\n // these checks to support server-side rendering use cases\n // @see https://github.com/WICG/focus-visible/issues/199\n if (typeof window !== 'undefined' && typeof document !== 'undefined') {\n // Make the polyfill helper globally available. This can be used as a signal\n // to interested libraries that wish to coordinate with the polyfill for e.g.,\n // applying the polyfill to a shadow root:\n window.applyFocusVisiblePolyfill = applyFocusVisiblePolyfill;\n\n // Notify interested libraries of the polyfill's presence, in case the\n // polyfill was loaded lazily:\n var event;\n\n try {\n event = new CustomEvent('focus-visible-polyfill-ready');\n } catch (error) {\n // IE11 does not support using CustomEvent as a constructor directly:\n event = document.createEvent('CustomEvent');\n event.initCustomEvent('focus-visible-polyfill-ready', false, false, {});\n }\n\n window.dispatchEvent(event);\n }\n\n if (typeof document !== 'undefined') {\n // Apply the polyfill to the global document, so that no JavaScript\n // coordination is required to use the polyfill in the top-level document:\n applyFocusVisiblePolyfill(document);\n }\n\n})));\n", "/*!\n * clipboard.js v2.0.11\n * https://clipboardjs.com/\n *\n * Licensed MIT \u00A9 Zeno Rocha\n */\n(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory();\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine([], factory);\n\telse if(typeof exports === 'object')\n\t\texports[\"ClipboardJS\"] = factory();\n\telse\n\t\troot[\"ClipboardJS\"] = factory();\n})(this, function() {\nreturn /******/ (function() { // webpackBootstrap\n/******/ \tvar __webpack_modules__ = ({\n\n/***/ 686:\n/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\n\n// EXPORTS\n__webpack_require__.d(__webpack_exports__, {\n \"default\": function() { return /* binding */ clipboard; }\n});\n\n// EXTERNAL MODULE: ./node_modules/tiny-emitter/index.js\nvar tiny_emitter = __webpack_require__(279);\nvar tiny_emitter_default = /*#__PURE__*/__webpack_require__.n(tiny_emitter);\n// EXTERNAL MODULE: ./node_modules/good-listener/src/listen.js\nvar listen = __webpack_require__(370);\nvar listen_default = /*#__PURE__*/__webpack_require__.n(listen);\n// EXTERNAL MODULE: ./node_modules/select/src/select.js\nvar src_select = __webpack_require__(817);\nvar select_default = /*#__PURE__*/__webpack_require__.n(src_select);\n;// CONCATENATED MODULE: ./src/common/command.js\n/**\n * Executes a given operation type.\n * @param {String} type\n * @return {Boolean}\n */\nfunction command(type) {\n try {\n return document.execCommand(type);\n } catch (err) {\n return false;\n }\n}\n;// CONCATENATED MODULE: ./src/actions/cut.js\n\n\n/**\n * Cut action wrapper.\n * @param {String|HTMLElement} target\n * @return {String}\n */\n\nvar ClipboardActionCut = function ClipboardActionCut(target) {\n var selectedText = select_default()(target);\n command('cut');\n return selectedText;\n};\n\n/* harmony default export */ var actions_cut = (ClipboardActionCut);\n;// CONCATENATED MODULE: ./src/common/create-fake-element.js\n/**\n * Creates a fake textarea element with a value.\n * @param {String} value\n * @return {HTMLElement}\n */\nfunction createFakeElement(value) {\n var isRTL = document.documentElement.getAttribute('dir') === 'rtl';\n var fakeElement = document.createElement('textarea'); // Prevent zooming on iOS\n\n fakeElement.style.fontSize = '12pt'; // Reset box model\n\n fakeElement.style.border = '0';\n fakeElement.style.padding = '0';\n fakeElement.style.margin = '0'; // Move element out of screen horizontally\n\n fakeElement.style.position = 'absolute';\n fakeElement.style[isRTL ? 'right' : 'left'] = '-9999px'; // Move element to the same position vertically\n\n var yPosition = window.pageYOffset || document.documentElement.scrollTop;\n fakeElement.style.top = \"\".concat(yPosition, \"px\");\n fakeElement.setAttribute('readonly', '');\n fakeElement.value = value;\n return fakeElement;\n}\n;// CONCATENATED MODULE: ./src/actions/copy.js\n\n\n\n/**\n * Create fake copy action wrapper using a fake element.\n * @param {String} target\n * @param {Object} options\n * @return {String}\n */\n\nvar fakeCopyAction = function fakeCopyAction(value, options) {\n var fakeElement = createFakeElement(value);\n options.container.appendChild(fakeElement);\n var selectedText = select_default()(fakeElement);\n command('copy');\n fakeElement.remove();\n return selectedText;\n};\n/**\n * Copy action wrapper.\n * @param {String|HTMLElement} target\n * @param {Object} options\n * @return {String}\n */\n\n\nvar ClipboardActionCopy = function ClipboardActionCopy(target) {\n var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {\n container: document.body\n };\n var selectedText = '';\n\n if (typeof target === 'string') {\n selectedText = fakeCopyAction(target, options);\n } else if (target instanceof HTMLInputElement && !['text', 'search', 'url', 'tel', 'password'].includes(target === null || target === void 0 ? void 0 : target.type)) {\n // If input type doesn't support `setSelectionRange`. Simulate it. https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement/setSelectionRange\n selectedText = fakeCopyAction(target.value, options);\n } else {\n selectedText = select_default()(target);\n command('copy');\n }\n\n return selectedText;\n};\n\n/* harmony default export */ var actions_copy = (ClipboardActionCopy);\n;// CONCATENATED MODULE: ./src/actions/default.js\nfunction _typeof(obj) { \"@babel/helpers - typeof\"; if (typeof Symbol === \"function\" && typeof Symbol.iterator === \"symbol\") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === \"function\" && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : typeof obj; }; } return _typeof(obj); }\n\n\n\n/**\n * Inner function which performs selection from either `text` or `target`\n * properties and then executes copy or cut operations.\n * @param {Object} options\n */\n\nvar ClipboardActionDefault = function ClipboardActionDefault() {\n var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n // Defines base properties passed from constructor.\n var _options$action = options.action,\n action = _options$action === void 0 ? 'copy' : _options$action,\n container = options.container,\n target = options.target,\n text = options.text; // Sets the `action` to be performed which can be either 'copy' or 'cut'.\n\n if (action !== 'copy' && action !== 'cut') {\n throw new Error('Invalid \"action\" value, use either \"copy\" or \"cut\"');\n } // Sets the `target` property using an element that will be have its content copied.\n\n\n if (target !== undefined) {\n if (target && _typeof(target) === 'object' && target.nodeType === 1) {\n if (action === 'copy' && target.hasAttribute('disabled')) {\n throw new Error('Invalid \"target\" attribute. Please use \"readonly\" instead of \"disabled\" attribute');\n }\n\n if (action === 'cut' && (target.hasAttribute('readonly') || target.hasAttribute('disabled'))) {\n throw new Error('Invalid \"target\" attribute. You can\\'t cut text from elements with \"readonly\" or \"disabled\" attributes');\n }\n } else {\n throw new Error('Invalid \"target\" value, use a valid Element');\n }\n } // Define selection strategy based on `text` property.\n\n\n if (text) {\n return actions_copy(text, {\n container: container\n });\n } // Defines which selection strategy based on `target` property.\n\n\n if (target) {\n return action === 'cut' ? actions_cut(target) : actions_copy(target, {\n container: container\n });\n }\n};\n\n/* harmony default export */ var actions_default = (ClipboardActionDefault);\n;// CONCATENATED MODULE: ./src/clipboard.js\nfunction clipboard_typeof(obj) { \"@babel/helpers - typeof\"; if (typeof Symbol === \"function\" && typeof Symbol.iterator === \"symbol\") { clipboard_typeof = function _typeof(obj) { return typeof obj; }; } else { clipboard_typeof = function _typeof(obj) { return obj && typeof Symbol === \"function\" && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : typeof obj; }; } return clipboard_typeof(obj); }\n\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nfunction _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\n\nfunction _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }\n\nfunction _inherits(subClass, superClass) { if (typeof superClass !== \"function\" && superClass !== null) { throw new TypeError(\"Super expression must either be null or a function\"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }\n\nfunction _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }\n\nfunction _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }\n\nfunction _possibleConstructorReturn(self, call) { if (call && (clipboard_typeof(call) === \"object\" || typeof call === \"function\")) { return call; } return _assertThisInitialized(self); }\n\nfunction _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError(\"this hasn't been initialised - super() hasn't been called\"); } return self; }\n\nfunction _isNativeReflectConstruct() { if (typeof Reflect === \"undefined\" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === \"function\") return true; try { Date.prototype.toString.call(Reflect.construct(Date, [], function () {})); return true; } catch (e) { return false; } }\n\nfunction _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }\n\n\n\n\n\n\n/**\n * Helper function to retrieve attribute value.\n * @param {String} suffix\n * @param {Element} element\n */\n\nfunction getAttributeValue(suffix, element) {\n var attribute = \"data-clipboard-\".concat(suffix);\n\n if (!element.hasAttribute(attribute)) {\n return;\n }\n\n return element.getAttribute(attribute);\n}\n/**\n * Base class which takes one or more elements, adds event listeners to them,\n * and instantiates a new `ClipboardAction` on each click.\n */\n\n\nvar Clipboard = /*#__PURE__*/function (_Emitter) {\n _inherits(Clipboard, _Emitter);\n\n var _super = _createSuper(Clipboard);\n\n /**\n * @param {String|HTMLElement|HTMLCollection|NodeList} trigger\n * @param {Object} options\n */\n function Clipboard(trigger, options) {\n var _this;\n\n _classCallCheck(this, Clipboard);\n\n _this = _super.call(this);\n\n _this.resolveOptions(options);\n\n _this.listenClick(trigger);\n\n return _this;\n }\n /**\n * Defines if attributes would be resolved using internal setter functions\n * or custom functions that were passed in the constructor.\n * @param {Object} options\n */\n\n\n _createClass(Clipboard, [{\n key: \"resolveOptions\",\n value: function resolveOptions() {\n var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n this.action = typeof options.action === 'function' ? options.action : this.defaultAction;\n this.target = typeof options.target === 'function' ? options.target : this.defaultTarget;\n this.text = typeof options.text === 'function' ? options.text : this.defaultText;\n this.container = clipboard_typeof(options.container) === 'object' ? options.container : document.body;\n }\n /**\n * Adds a click event listener to the passed trigger.\n * @param {String|HTMLElement|HTMLCollection|NodeList} trigger\n */\n\n }, {\n key: \"listenClick\",\n value: function listenClick(trigger) {\n var _this2 = this;\n\n this.listener = listen_default()(trigger, 'click', function (e) {\n return _this2.onClick(e);\n });\n }\n /**\n * Defines a new `ClipboardAction` on each click event.\n * @param {Event} e\n */\n\n }, {\n key: \"onClick\",\n value: function onClick(e) {\n var trigger = e.delegateTarget || e.currentTarget;\n var action = this.action(trigger) || 'copy';\n var text = actions_default({\n action: action,\n container: this.container,\n target: this.target(trigger),\n text: this.text(trigger)\n }); // Fires an event based on the copy operation result.\n\n this.emit(text ? 'success' : 'error', {\n action: action,\n text: text,\n trigger: trigger,\n clearSelection: function clearSelection() {\n if (trigger) {\n trigger.focus();\n }\n\n window.getSelection().removeAllRanges();\n }\n });\n }\n /**\n * Default `action` lookup function.\n * @param {Element} trigger\n */\n\n }, {\n key: \"defaultAction\",\n value: function defaultAction(trigger) {\n return getAttributeValue('action', trigger);\n }\n /**\n * Default `target` lookup function.\n * @param {Element} trigger\n */\n\n }, {\n key: \"defaultTarget\",\n value: function defaultTarget(trigger) {\n var selector = getAttributeValue('target', trigger);\n\n if (selector) {\n return document.querySelector(selector);\n }\n }\n /**\n * Allow fire programmatically a copy action\n * @param {String|HTMLElement} target\n * @param {Object} options\n * @returns Text copied.\n */\n\n }, {\n key: \"defaultText\",\n\n /**\n * Default `text` lookup function.\n * @param {Element} trigger\n */\n value: function defaultText(trigger) {\n return getAttributeValue('text', trigger);\n }\n /**\n * Destroy lifecycle.\n */\n\n }, {\n key: \"destroy\",\n value: function destroy() {\n this.listener.destroy();\n }\n }], [{\n key: \"copy\",\n value: function copy(target) {\n var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {\n container: document.body\n };\n return actions_copy(target, options);\n }\n /**\n * Allow fire programmatically a cut action\n * @param {String|HTMLElement} target\n * @returns Text cutted.\n */\n\n }, {\n key: \"cut\",\n value: function cut(target) {\n return actions_cut(target);\n }\n /**\n * Returns the support of the given action, or all actions if no action is\n * given.\n * @param {String} [action]\n */\n\n }, {\n key: \"isSupported\",\n value: function isSupported() {\n var action = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : ['copy', 'cut'];\n var actions = typeof action === 'string' ? [action] : action;\n var support = !!document.queryCommandSupported;\n actions.forEach(function (action) {\n support = support && !!document.queryCommandSupported(action);\n });\n return support;\n }\n }]);\n\n return Clipboard;\n}((tiny_emitter_default()));\n\n/* harmony default export */ var clipboard = (Clipboard);\n\n/***/ }),\n\n/***/ 828:\n/***/ (function(module) {\n\nvar DOCUMENT_NODE_TYPE = 9;\n\n/**\n * A polyfill for Element.matches()\n */\nif (typeof Element !== 'undefined' && !Element.prototype.matches) {\n var proto = Element.prototype;\n\n proto.matches = proto.matchesSelector ||\n proto.mozMatchesSelector ||\n proto.msMatchesSelector ||\n proto.oMatchesSelector ||\n proto.webkitMatchesSelector;\n}\n\n/**\n * Finds the closest parent that matches a selector.\n *\n * @param {Element} element\n * @param {String} selector\n * @return {Function}\n */\nfunction closest (element, selector) {\n while (element && element.nodeType !== DOCUMENT_NODE_TYPE) {\n if (typeof element.matches === 'function' &&\n element.matches(selector)) {\n return element;\n }\n element = element.parentNode;\n }\n}\n\nmodule.exports = closest;\n\n\n/***/ }),\n\n/***/ 438:\n/***/ (function(module, __unused_webpack_exports, __webpack_require__) {\n\nvar closest = __webpack_require__(828);\n\n/**\n * Delegates event to a selector.\n *\n * @param {Element} element\n * @param {String} selector\n * @param {String} type\n * @param {Function} callback\n * @param {Boolean} useCapture\n * @return {Object}\n */\nfunction _delegate(element, selector, type, callback, useCapture) {\n var listenerFn = listener.apply(this, arguments);\n\n element.addEventListener(type, listenerFn, useCapture);\n\n return {\n destroy: function() {\n element.removeEventListener(type, listenerFn, useCapture);\n }\n }\n}\n\n/**\n * Delegates event to a selector.\n *\n * @param {Element|String|Array} [elements]\n * @param {String} selector\n * @param {String} type\n * @param {Function} callback\n * @param {Boolean} useCapture\n * @return {Object}\n */\nfunction delegate(elements, selector, type, callback, useCapture) {\n // Handle the regular Element usage\n if (typeof elements.addEventListener === 'function') {\n return _delegate.apply(null, arguments);\n }\n\n // Handle Element-less usage, it defaults to global delegation\n if (typeof type === 'function') {\n // Use `document` as the first parameter, then apply arguments\n // This is a short way to .unshift `arguments` without running into deoptimizations\n return _delegate.bind(null, document).apply(null, arguments);\n }\n\n // Handle Selector-based usage\n if (typeof elements === 'string') {\n elements = document.querySelectorAll(elements);\n }\n\n // Handle Array-like based usage\n return Array.prototype.map.call(elements, function (element) {\n return _delegate(element, selector, type, callback, useCapture);\n });\n}\n\n/**\n * Finds closest match and invokes callback.\n *\n * @param {Element} element\n * @param {String} selector\n * @param {String} type\n * @param {Function} callback\n * @return {Function}\n */\nfunction listener(element, selector, type, callback) {\n return function(e) {\n e.delegateTarget = closest(e.target, selector);\n\n if (e.delegateTarget) {\n callback.call(element, e);\n }\n }\n}\n\nmodule.exports = delegate;\n\n\n/***/ }),\n\n/***/ 879:\n/***/ (function(__unused_webpack_module, exports) {\n\n/**\n * Check if argument is a HTML element.\n *\n * @param {Object} value\n * @return {Boolean}\n */\nexports.node = function(value) {\n return value !== undefined\n && value instanceof HTMLElement\n && value.nodeType === 1;\n};\n\n/**\n * Check if argument is a list of HTML elements.\n *\n * @param {Object} value\n * @return {Boolean}\n */\nexports.nodeList = function(value) {\n var type = Object.prototype.toString.call(value);\n\n return value !== undefined\n && (type === '[object NodeList]' || type === '[object HTMLCollection]')\n && ('length' in value)\n && (value.length === 0 || exports.node(value[0]));\n};\n\n/**\n * Check if argument is a string.\n *\n * @param {Object} value\n * @return {Boolean}\n */\nexports.string = function(value) {\n return typeof value === 'string'\n || value instanceof String;\n};\n\n/**\n * Check if argument is a function.\n *\n * @param {Object} value\n * @return {Boolean}\n */\nexports.fn = function(value) {\n var type = Object.prototype.toString.call(value);\n\n return type === '[object Function]';\n};\n\n\n/***/ }),\n\n/***/ 370:\n/***/ (function(module, __unused_webpack_exports, __webpack_require__) {\n\nvar is = __webpack_require__(879);\nvar delegate = __webpack_require__(438);\n\n/**\n * Validates all params and calls the right\n * listener function based on its target type.\n *\n * @param {String|HTMLElement|HTMLCollection|NodeList} target\n * @param {String} type\n * @param {Function} callback\n * @return {Object}\n */\nfunction listen(target, type, callback) {\n if (!target && !type && !callback) {\n throw new Error('Missing required arguments');\n }\n\n if (!is.string(type)) {\n throw new TypeError('Second argument must be a String');\n }\n\n if (!is.fn(callback)) {\n throw new TypeError('Third argument must be a Function');\n }\n\n if (is.node(target)) {\n return listenNode(target, type, callback);\n }\n else if (is.nodeList(target)) {\n return listenNodeList(target, type, callback);\n }\n else if (is.string(target)) {\n return listenSelector(target, type, callback);\n }\n else {\n throw new TypeError('First argument must be a String, HTMLElement, HTMLCollection, or NodeList');\n }\n}\n\n/**\n * Adds an event listener to a HTML element\n * and returns a remove listener function.\n *\n * @param {HTMLElement} node\n * @param {String} type\n * @param {Function} callback\n * @return {Object}\n */\nfunction listenNode(node, type, callback) {\n node.addEventListener(type, callback);\n\n return {\n destroy: function() {\n node.removeEventListener(type, callback);\n }\n }\n}\n\n/**\n * Add an event listener to a list of HTML elements\n * and returns a remove listener function.\n *\n * @param {NodeList|HTMLCollection} nodeList\n * @param {String} type\n * @param {Function} callback\n * @return {Object}\n */\nfunction listenNodeList(nodeList, type, callback) {\n Array.prototype.forEach.call(nodeList, function(node) {\n node.addEventListener(type, callback);\n });\n\n return {\n destroy: function() {\n Array.prototype.forEach.call(nodeList, function(node) {\n node.removeEventListener(type, callback);\n });\n }\n }\n}\n\n/**\n * Add an event listener to a selector\n * and returns a remove listener function.\n *\n * @param {String} selector\n * @param {String} type\n * @param {Function} callback\n * @return {Object}\n */\nfunction listenSelector(selector, type, callback) {\n return delegate(document.body, selector, type, callback);\n}\n\nmodule.exports = listen;\n\n\n/***/ }),\n\n/***/ 817:\n/***/ (function(module) {\n\nfunction select(element) {\n var selectedText;\n\n if (element.nodeName === 'SELECT') {\n element.focus();\n\n selectedText = element.value;\n }\n else if (element.nodeName === 'INPUT' || element.nodeName === 'TEXTAREA') {\n var isReadOnly = element.hasAttribute('readonly');\n\n if (!isReadOnly) {\n element.setAttribute('readonly', '');\n }\n\n element.select();\n element.setSelectionRange(0, element.value.length);\n\n if (!isReadOnly) {\n element.removeAttribute('readonly');\n }\n\n selectedText = element.value;\n }\n else {\n if (element.hasAttribute('contenteditable')) {\n element.focus();\n }\n\n var selection = window.getSelection();\n var range = document.createRange();\n\n range.selectNodeContents(element);\n selection.removeAllRanges();\n selection.addRange(range);\n\n selectedText = selection.toString();\n }\n\n return selectedText;\n}\n\nmodule.exports = select;\n\n\n/***/ }),\n\n/***/ 279:\n/***/ (function(module) {\n\nfunction E () {\n // Keep this empty so it's easier to inherit from\n // (via https://github.com/lipsmack from https://github.com/scottcorgan/tiny-emitter/issues/3)\n}\n\nE.prototype = {\n on: function (name, callback, ctx) {\n var e = this.e || (this.e = {});\n\n (e[name] || (e[name] = [])).push({\n fn: callback,\n ctx: ctx\n });\n\n return this;\n },\n\n once: function (name, callback, ctx) {\n var self = this;\n function listener () {\n self.off(name, listener);\n callback.apply(ctx, arguments);\n };\n\n listener._ = callback\n return this.on(name, listener, ctx);\n },\n\n emit: function (name) {\n var data = [].slice.call(arguments, 1);\n var evtArr = ((this.e || (this.e = {}))[name] || []).slice();\n var i = 0;\n var len = evtArr.length;\n\n for (i; i < len; i++) {\n evtArr[i].fn.apply(evtArr[i].ctx, data);\n }\n\n return this;\n },\n\n off: function (name, callback) {\n var e = this.e || (this.e = {});\n var evts = e[name];\n var liveEvents = [];\n\n if (evts && callback) {\n for (var i = 0, len = evts.length; i < len; i++) {\n if (evts[i].fn !== callback && evts[i].fn._ !== callback)\n liveEvents.push(evts[i]);\n }\n }\n\n // Remove event from queue to prevent memory leak\n // Suggested by https://github.com/lazd\n // Ref: https://github.com/scottcorgan/tiny-emitter/commit/c6ebfaa9bc973b33d110a84a307742b7cf94c953#commitcomment-5024910\n\n (liveEvents.length)\n ? e[name] = liveEvents\n : delete e[name];\n\n return this;\n }\n};\n\nmodule.exports = E;\nmodule.exports.TinyEmitter = E;\n\n\n/***/ })\n\n/******/ \t});\n/************************************************************************/\n/******/ \t// The module cache\n/******/ \tvar __webpack_module_cache__ = {};\n/******/ \t\n/******/ \t// The require function\n/******/ \tfunction __webpack_require__(moduleId) {\n/******/ \t\t// Check if module is in cache\n/******/ \t\tif(__webpack_module_cache__[moduleId]) {\n/******/ \t\t\treturn __webpack_module_cache__[moduleId].exports;\n/******/ \t\t}\n/******/ \t\t// Create a new module (and put it into the cache)\n/******/ \t\tvar module = __webpack_module_cache__[moduleId] = {\n/******/ \t\t\t// no module.id needed\n/******/ \t\t\t// no module.loaded needed\n/******/ \t\t\texports: {}\n/******/ \t\t};\n/******/ \t\n/******/ \t\t// Execute the module function\n/******/ \t\t__webpack_modules__[moduleId](module, module.exports, __webpack_require__);\n/******/ \t\n/******/ \t\t// Return the exports of the module\n/******/ \t\treturn module.exports;\n/******/ \t}\n/******/ \t\n/************************************************************************/\n/******/ \t/* webpack/runtime/compat get default export */\n/******/ \t!function() {\n/******/ \t\t// getDefaultExport function for compatibility with non-harmony modules\n/******/ \t\t__webpack_require__.n = function(module) {\n/******/ \t\t\tvar getter = module && module.__esModule ?\n/******/ \t\t\t\tfunction() { return module['default']; } :\n/******/ \t\t\t\tfunction() { return module; };\n/******/ \t\t\t__webpack_require__.d(getter, { a: getter });\n/******/ \t\t\treturn getter;\n/******/ \t\t};\n/******/ \t}();\n/******/ \t\n/******/ \t/* webpack/runtime/define property getters */\n/******/ \t!function() {\n/******/ \t\t// define getter functions for harmony exports\n/******/ \t\t__webpack_require__.d = function(exports, definition) {\n/******/ \t\t\tfor(var key in definition) {\n/******/ \t\t\t\tif(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n/******/ \t\t\t\t\tObject.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n/******/ \t\t\t\t}\n/******/ \t\t\t}\n/******/ \t\t};\n/******/ \t}();\n/******/ \t\n/******/ \t/* webpack/runtime/hasOwnProperty shorthand */\n/******/ \t!function() {\n/******/ \t\t__webpack_require__.o = function(obj, prop) { return Object.prototype.hasOwnProperty.call(obj, prop); }\n/******/ \t}();\n/******/ \t\n/************************************************************************/\n/******/ \t// module exports must be returned from runtime so entry inlining is disabled\n/******/ \t// startup\n/******/ \t// Load entry module and return exports\n/******/ \treturn __webpack_require__(686);\n/******/ })()\n.default;\n});", "/*!\n * escape-html\n * Copyright(c) 2012-2013 TJ Holowaychuk\n * Copyright(c) 2015 Andreas Lubbe\n * Copyright(c) 2015 Tiancheng \"Timothy\" Gu\n * MIT Licensed\n */\n\n'use strict';\n\n/**\n * Module variables.\n * @private\n */\n\nvar matchHtmlRegExp = /[\"'&<>]/;\n\n/**\n * Module exports.\n * @public\n */\n\nmodule.exports = escapeHtml;\n\n/**\n * Escape special characters in the given string of html.\n *\n * @param {string} string The string to escape for inserting into HTML\n * @return {string}\n * @public\n */\n\nfunction escapeHtml(string) {\n var str = '' + string;\n var match = matchHtmlRegExp.exec(str);\n\n if (!match) {\n return str;\n }\n\n var escape;\n var html = '';\n var index = 0;\n var lastIndex = 0;\n\n for (index = match.index; index < str.length; index++) {\n switch (str.charCodeAt(index)) {\n case 34: // \"\n escape = '"';\n break;\n case 38: // &\n escape = '&';\n break;\n case 39: // '\n escape = ''';\n break;\n case 60: // <\n escape = '<';\n break;\n case 62: // >\n escape = '>';\n break;\n default:\n continue;\n }\n\n if (lastIndex !== index) {\n html += str.substring(lastIndex, index);\n }\n\n lastIndex = index + 1;\n html += escape;\n }\n\n return lastIndex !== index\n ? html + str.substring(lastIndex, index)\n : html;\n}\n", "/*\n * Copyright (c) 2016-2023 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport \"focus-visible\"\n\nimport {\n EMPTY,\n NEVER,\n Observable,\n Subject,\n defer,\n delay,\n filter,\n map,\n merge,\n mergeWith,\n shareReplay,\n switchMap\n} from \"rxjs\"\n\nimport { configuration, feature } from \"./_\"\nimport {\n at,\n getActiveElement,\n getOptionalElement,\n requestJSON,\n setLocation,\n setToggle,\n watchDocument,\n watchKeyboard,\n watchLocation,\n watchLocationTarget,\n watchMedia,\n watchPrint,\n watchScript,\n watchViewport\n} from \"./browser\"\nimport {\n getComponentElement,\n getComponentElements,\n mountAnnounce,\n mountBackToTop,\n mountConsent,\n mountContent,\n mountDialog,\n mountHeader,\n mountHeaderTitle,\n mountPalette,\n mountProgress,\n mountSearch,\n mountSearchHiglight,\n mountSidebar,\n mountSource,\n mountTableOfContents,\n mountTabs,\n watchHeader,\n watchMain\n} from \"./components\"\nimport {\n SearchIndex,\n setupClipboardJS,\n setupInstantNavigation,\n setupVersionSelector\n} from \"./integrations\"\nimport {\n patchEllipsis,\n patchIndeterminate,\n patchScrollfix,\n patchScrolllock\n} from \"./patches\"\nimport \"./polyfills\"\n\n/* ----------------------------------------------------------------------------\n * Functions - @todo refactor\n * ------------------------------------------------------------------------- */\n\n/**\n * Fetch search index\n *\n * @returns Search index observable\n */\nfunction fetchSearchIndex(): Observable {\n if (location.protocol === \"file:\") {\n return watchScript(\n `${new URL(\"search/search_index.js\", config.base)}`\n )\n .pipe(\n // @ts-ignore - @todo fix typings\n map(() => __index),\n shareReplay(1)\n )\n } else {\n return requestJSON(\n new URL(\"search/search_index.json\", config.base)\n )\n }\n}\n\n/* ----------------------------------------------------------------------------\n * Application\n * ------------------------------------------------------------------------- */\n\n/* Yay, JavaScript is available */\ndocument.documentElement.classList.remove(\"no-js\")\ndocument.documentElement.classList.add(\"js\")\n\n/* Set up navigation observables and subjects */\nconst document$ = watchDocument()\nconst location$ = watchLocation()\nconst target$ = watchLocationTarget(location$)\nconst keyboard$ = watchKeyboard()\n\n/* Set up media observables */\nconst viewport$ = watchViewport()\nconst tablet$ = watchMedia(\"(min-width: 960px)\")\nconst screen$ = watchMedia(\"(min-width: 1220px)\")\nconst print$ = watchPrint()\n\n/* Retrieve search index, if search is enabled */\nconst config = configuration()\nconst index$ = document.forms.namedItem(\"search\")\n ? fetchSearchIndex()\n : NEVER\n\n/* Set up Clipboard.js integration */\nconst alert$ = new Subject()\nsetupClipboardJS({ alert$ })\n\n/* Set up progress indicator */\nconst progress$ = new Subject()\n\n/* Set up instant navigation, if enabled */\nif (feature(\"navigation.instant\"))\n setupInstantNavigation({ location$, viewport$, progress$ })\n .subscribe(document$)\n\n/* Set up version selector */\nif (config.version?.provider === \"mike\")\n setupVersionSelector({ document$ })\n\n/* Always close drawer and search on navigation */\nmerge(location$, target$)\n .pipe(\n delay(125)\n )\n .subscribe(() => {\n setToggle(\"drawer\", false)\n setToggle(\"search\", false)\n })\n\n/* Set up global keyboard handlers */\nkeyboard$\n .pipe(\n filter(({ mode }) => mode === \"global\")\n )\n .subscribe(key => {\n switch (key.type) {\n\n /* Go to previous page */\n case \"p\":\n case \",\":\n const prev = getOptionalElement(\"link[rel=prev]\")\n if (typeof prev !== \"undefined\")\n setLocation(prev)\n break\n\n /* Go to next page */\n case \"n\":\n case \".\":\n const next = getOptionalElement(\"link[rel=next]\")\n if (typeof next !== \"undefined\")\n setLocation(next)\n break\n\n /* Expand navigation, see https://bit.ly/3ZjG5io */\n case \"Enter\":\n const active = getActiveElement()\n if (active instanceof HTMLLabelElement)\n active.click()\n }\n })\n\n/* Set up patches */\npatchEllipsis({ document$ })\npatchIndeterminate({ document$, tablet$ })\npatchScrollfix({ document$ })\npatchScrolllock({ viewport$, tablet$ })\n\n/* Set up header and main area observable */\nconst header$ = watchHeader(getComponentElement(\"header\"), { viewport$ })\nconst main$ = document$\n .pipe(\n map(() => getComponentElement(\"main\")),\n switchMap(el => watchMain(el, { viewport$, header$ })),\n shareReplay(1)\n )\n\n/* Set up control component observables */\nconst control$ = merge(\n\n /* Consent */\n ...getComponentElements(\"consent\")\n .map(el => mountConsent(el, { target$ })),\n\n /* Dialog */\n ...getComponentElements(\"dialog\")\n .map(el => mountDialog(el, { alert$ })),\n\n /* Header */\n ...getComponentElements(\"header\")\n .map(el => mountHeader(el, { viewport$, header$, main$ })),\n\n /* Color palette */\n ...getComponentElements(\"palette\")\n .map(el => mountPalette(el)),\n\n /* Progress bar */\n ...getComponentElements(\"progress\")\n .map(el => mountProgress(el, { progress$ })),\n\n /* Search */\n ...getComponentElements(\"search\")\n .map(el => mountSearch(el, { index$, keyboard$ })),\n\n /* Repository information */\n ...getComponentElements(\"source\")\n .map(el => mountSource(el))\n)\n\n/* Set up content component observables */\nconst content$ = defer(() => merge(\n\n /* Announcement bar */\n ...getComponentElements(\"announce\")\n .map(el => mountAnnounce(el)),\n\n /* Content */\n ...getComponentElements(\"content\")\n .map(el => mountContent(el, { viewport$, target$, print$ })),\n\n /* Search highlighting */\n ...getComponentElements(\"content\")\n .map(el => feature(\"search.highlight\")\n ? mountSearchHiglight(el, { index$, location$ })\n : EMPTY\n ),\n\n /* Header title */\n ...getComponentElements(\"header-title\")\n .map(el => mountHeaderTitle(el, { viewport$, header$ })),\n\n /* Sidebar */\n ...getComponentElements(\"sidebar\")\n .map(el => el.getAttribute(\"data-md-type\") === \"navigation\"\n ? at(screen$, () => mountSidebar(el, { viewport$, header$, main$ }))\n : at(tablet$, () => mountSidebar(el, { viewport$, header$, main$ }))\n ),\n\n /* Navigation tabs */\n ...getComponentElements(\"tabs\")\n .map(el => mountTabs(el, { viewport$, header$ })),\n\n /* Table of contents */\n ...getComponentElements(\"toc\")\n .map(el => mountTableOfContents(el, {\n viewport$, header$, main$, target$\n })),\n\n /* Back-to-top button */\n ...getComponentElements(\"top\")\n .map(el => mountBackToTop(el, { viewport$, header$, main$, target$ }))\n))\n\n/* Set up component observables */\nconst component$ = document$\n .pipe(\n switchMap(() => content$),\n mergeWith(control$),\n shareReplay(1)\n )\n\n/* Subscribe to all components */\ncomponent$.subscribe()\n\n/* ----------------------------------------------------------------------------\n * Exports\n * ------------------------------------------------------------------------- */\n\nwindow.document$ = document$ /* Document observable */\nwindow.location$ = location$ /* Location subject */\nwindow.target$ = target$ /* Location target observable */\nwindow.keyboard$ = keyboard$ /* Keyboard observable */\nwindow.viewport$ = viewport$ /* Viewport observable */\nwindow.tablet$ = tablet$ /* Media tablet observable */\nwindow.screen$ = screen$ /* Media screen observable */\nwindow.print$ = print$ /* Media print observable */\nwindow.alert$ = alert$ /* Alert subject */\nwindow.progress$ = progress$ /* Progress indicator subject */\nwindow.component$ = component$ /* Component observable */\n", "/*! *****************************************************************************\r\nCopyright (c) Microsoft Corporation.\r\n\r\nPermission to use, copy, modify, and/or distribute this software for any\r\npurpose with or without fee is hereby granted.\r\n\r\nTHE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH\r\nREGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY\r\nAND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,\r\nINDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM\r\nLOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR\r\nOTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR\r\nPERFORMANCE OF THIS SOFTWARE.\r\n***************************************************************************** */\r\n/* global Reflect, Promise */\r\n\r\nvar extendStatics = function(d, b) {\r\n extendStatics = Object.setPrototypeOf ||\r\n ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||\r\n function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };\r\n return extendStatics(d, b);\r\n};\r\n\r\nexport function __extends(d, b) {\r\n if (typeof b !== \"function\" && b !== null)\r\n throw new TypeError(\"Class extends value \" + String(b) + \" is not a constructor or null\");\r\n extendStatics(d, b);\r\n function __() { this.constructor = d; }\r\n d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());\r\n}\r\n\r\nexport var __assign = function() {\r\n __assign = Object.assign || function __assign(t) {\r\n for (var s, i = 1, n = arguments.length; i < n; i++) {\r\n s = arguments[i];\r\n for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];\r\n }\r\n return t;\r\n }\r\n return __assign.apply(this, arguments);\r\n}\r\n\r\nexport function __rest(s, e) {\r\n var t = {};\r\n for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)\r\n t[p] = s[p];\r\n if (s != null && typeof Object.getOwnPropertySymbols === \"function\")\r\n for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {\r\n if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))\r\n t[p[i]] = s[p[i]];\r\n }\r\n return t;\r\n}\r\n\r\nexport function __decorate(decorators, target, key, desc) {\r\n var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;\r\n if (typeof Reflect === \"object\" && typeof Reflect.decorate === \"function\") r = Reflect.decorate(decorators, target, key, desc);\r\n else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;\r\n return c > 3 && r && Object.defineProperty(target, key, r), r;\r\n}\r\n\r\nexport function __param(paramIndex, decorator) {\r\n return function (target, key) { decorator(target, key, paramIndex); }\r\n}\r\n\r\nexport function __metadata(metadataKey, metadataValue) {\r\n if (typeof Reflect === \"object\" && typeof Reflect.metadata === \"function\") return Reflect.metadata(metadataKey, metadataValue);\r\n}\r\n\r\nexport function __awaiter(thisArg, _arguments, P, generator) {\r\n function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }\r\n return new (P || (P = Promise))(function (resolve, reject) {\r\n function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }\r\n function rejected(value) { try { step(generator[\"throw\"](value)); } catch (e) { reject(e); } }\r\n function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }\r\n step((generator = generator.apply(thisArg, _arguments || [])).next());\r\n });\r\n}\r\n\r\nexport function __generator(thisArg, body) {\r\n var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;\r\n return g = { next: verb(0), \"throw\": verb(1), \"return\": verb(2) }, typeof Symbol === \"function\" && (g[Symbol.iterator] = function() { return this; }), g;\r\n function verb(n) { return function (v) { return step([n, v]); }; }\r\n function step(op) {\r\n if (f) throw new TypeError(\"Generator is already executing.\");\r\n while (_) try {\r\n if (f = 1, y && (t = op[0] & 2 ? y[\"return\"] : op[0] ? y[\"throw\"] || ((t = y[\"return\"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;\r\n if (y = 0, t) op = [op[0] & 2, t.value];\r\n switch (op[0]) {\r\n case 0: case 1: t = op; break;\r\n case 4: _.label++; return { value: op[1], done: false };\r\n case 5: _.label++; y = op[1]; op = [0]; continue;\r\n case 7: op = _.ops.pop(); _.trys.pop(); continue;\r\n default:\r\n if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }\r\n if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }\r\n if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }\r\n if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }\r\n if (t[2]) _.ops.pop();\r\n _.trys.pop(); continue;\r\n }\r\n op = body.call(thisArg, _);\r\n } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }\r\n if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };\r\n }\r\n}\r\n\r\nexport var __createBinding = Object.create ? (function(o, m, k, k2) {\r\n if (k2 === undefined) k2 = k;\r\n Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });\r\n}) : (function(o, m, k, k2) {\r\n if (k2 === undefined) k2 = k;\r\n o[k2] = m[k];\r\n});\r\n\r\nexport function __exportStar(m, o) {\r\n for (var p in m) if (p !== \"default\" && !Object.prototype.hasOwnProperty.call(o, p)) __createBinding(o, m, p);\r\n}\r\n\r\nexport function __values(o) {\r\n var s = typeof Symbol === \"function\" && Symbol.iterator, m = s && o[s], i = 0;\r\n if (m) return m.call(o);\r\n if (o && typeof o.length === \"number\") return {\r\n next: function () {\r\n if (o && i >= o.length) o = void 0;\r\n return { value: o && o[i++], done: !o };\r\n }\r\n };\r\n throw new TypeError(s ? \"Object is not iterable.\" : \"Symbol.iterator is not defined.\");\r\n}\r\n\r\nexport function __read(o, n) {\r\n var m = typeof Symbol === \"function\" && o[Symbol.iterator];\r\n if (!m) return o;\r\n var i = m.call(o), r, ar = [], e;\r\n try {\r\n while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);\r\n }\r\n catch (error) { e = { error: error }; }\r\n finally {\r\n try {\r\n if (r && !r.done && (m = i[\"return\"])) m.call(i);\r\n }\r\n finally { if (e) throw e.error; }\r\n }\r\n return ar;\r\n}\r\n\r\n/** @deprecated */\r\nexport function __spread() {\r\n for (var ar = [], i = 0; i < arguments.length; i++)\r\n ar = ar.concat(__read(arguments[i]));\r\n return ar;\r\n}\r\n\r\n/** @deprecated */\r\nexport function __spreadArrays() {\r\n for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length;\r\n for (var r = Array(s), k = 0, i = 0; i < il; i++)\r\n for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++)\r\n r[k] = a[j];\r\n return r;\r\n}\r\n\r\nexport function __spreadArray(to, from, pack) {\r\n if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {\r\n if (ar || !(i in from)) {\r\n if (!ar) ar = Array.prototype.slice.call(from, 0, i);\r\n ar[i] = from[i];\r\n }\r\n }\r\n return to.concat(ar || Array.prototype.slice.call(from));\r\n}\r\n\r\nexport function __await(v) {\r\n return this instanceof __await ? (this.v = v, this) : new __await(v);\r\n}\r\n\r\nexport function __asyncGenerator(thisArg, _arguments, generator) {\r\n if (!Symbol.asyncIterator) throw new TypeError(\"Symbol.asyncIterator is not defined.\");\r\n var g = generator.apply(thisArg, _arguments || []), i, q = [];\r\n return i = {}, verb(\"next\"), verb(\"throw\"), verb(\"return\"), i[Symbol.asyncIterator] = function () { return this; }, i;\r\n function verb(n) { if (g[n]) i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; }\r\n function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(q[0][3], e); } }\r\n function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); }\r\n function fulfill(value) { resume(\"next\", value); }\r\n function reject(value) { resume(\"throw\", value); }\r\n function settle(f, v) { if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]); }\r\n}\r\n\r\nexport function __asyncDelegator(o) {\r\n var i, p;\r\n return i = {}, verb(\"next\"), verb(\"throw\", function (e) { throw e; }), verb(\"return\"), i[Symbol.iterator] = function () { return this; }, i;\r\n function verb(n, f) { i[n] = o[n] ? function (v) { return (p = !p) ? { value: __await(o[n](v)), done: n === \"return\" } : f ? f(v) : v; } : f; }\r\n}\r\n\r\nexport function __asyncValues(o) {\r\n if (!Symbol.asyncIterator) throw new TypeError(\"Symbol.asyncIterator is not defined.\");\r\n var m = o[Symbol.asyncIterator], i;\r\n return m ? m.call(o) : (o = typeof __values === \"function\" ? __values(o) : o[Symbol.iterator](), i = {}, verb(\"next\"), verb(\"throw\"), verb(\"return\"), i[Symbol.asyncIterator] = function () { return this; }, i);\r\n function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; }\r\n function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }\r\n}\r\n\r\nexport function __makeTemplateObject(cooked, raw) {\r\n if (Object.defineProperty) { Object.defineProperty(cooked, \"raw\", { value: raw }); } else { cooked.raw = raw; }\r\n return cooked;\r\n};\r\n\r\nvar __setModuleDefault = Object.create ? (function(o, v) {\r\n Object.defineProperty(o, \"default\", { enumerable: true, value: v });\r\n}) : function(o, v) {\r\n o[\"default\"] = v;\r\n};\r\n\r\nexport function __importStar(mod) {\r\n if (mod && mod.__esModule) return mod;\r\n var result = {};\r\n if (mod != null) for (var k in mod) if (k !== \"default\" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);\r\n __setModuleDefault(result, mod);\r\n return result;\r\n}\r\n\r\nexport function __importDefault(mod) {\r\n return (mod && mod.__esModule) ? mod : { default: mod };\r\n}\r\n\r\nexport function __classPrivateFieldGet(receiver, state, kind, f) {\r\n if (kind === \"a\" && !f) throw new TypeError(\"Private accessor was defined without a getter\");\r\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\r\n return kind === \"m\" ? f : kind === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\r\n}\r\n\r\nexport function __classPrivateFieldSet(receiver, state, value, kind, f) {\r\n if (kind === \"m\") throw new TypeError(\"Private method is not writable\");\r\n if (kind === \"a\" && !f) throw new TypeError(\"Private accessor was defined without a setter\");\r\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\r\n return (kind === \"a\" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;\r\n}\r\n", "/**\n * Returns true if the object is a function.\n * @param value The value to check\n */\nexport function isFunction(value: any): value is (...args: any[]) => any {\n return typeof value === 'function';\n}\n", "/**\n * Used to create Error subclasses until the community moves away from ES5.\n *\n * This is because compiling from TypeScript down to ES5 has issues with subclassing Errors\n * as well as other built-in types: https://github.com/Microsoft/TypeScript/issues/12123\n *\n * @param createImpl A factory function to create the actual constructor implementation. The returned\n * function should be a named function that calls `_super` internally.\n */\nexport function createErrorClass(createImpl: (_super: any) => any): T {\n const _super = (instance: any) => {\n Error.call(instance);\n instance.stack = new Error().stack;\n };\n\n const ctorFunc = createImpl(_super);\n ctorFunc.prototype = Object.create(Error.prototype);\n ctorFunc.prototype.constructor = ctorFunc;\n return ctorFunc;\n}\n", "import { createErrorClass } from './createErrorClass';\n\nexport interface UnsubscriptionError extends Error {\n readonly errors: any[];\n}\n\nexport interface UnsubscriptionErrorCtor {\n /**\n * @deprecated Internal implementation detail. Do not construct error instances.\n * Cannot be tagged as internal: https://github.com/ReactiveX/rxjs/issues/6269\n */\n new (errors: any[]): UnsubscriptionError;\n}\n\n/**\n * An error thrown when one or more errors have occurred during the\n * `unsubscribe` of a {@link Subscription}.\n */\nexport const UnsubscriptionError: UnsubscriptionErrorCtor = createErrorClass(\n (_super) =>\n function UnsubscriptionErrorImpl(this: any, errors: (Error | string)[]) {\n _super(this);\n this.message = errors\n ? `${errors.length} errors occurred during unsubscription:\n${errors.map((err, i) => `${i + 1}) ${err.toString()}`).join('\\n ')}`\n : '';\n this.name = 'UnsubscriptionError';\n this.errors = errors;\n }\n);\n", "/**\n * Removes an item from an array, mutating it.\n * @param arr The array to remove the item from\n * @param item The item to remove\n */\nexport function arrRemove(arr: T[] | undefined | null, item: T) {\n if (arr) {\n const index = arr.indexOf(item);\n 0 <= index && arr.splice(index, 1);\n }\n}\n", "import { isFunction } from './util/isFunction';\nimport { UnsubscriptionError } from './util/UnsubscriptionError';\nimport { SubscriptionLike, TeardownLogic, Unsubscribable } from './types';\nimport { arrRemove } from './util/arrRemove';\n\n/**\n * Represents a disposable resource, such as the execution of an Observable. A\n * Subscription has one important method, `unsubscribe`, that takes no argument\n * and just disposes the resource held by the subscription.\n *\n * Additionally, subscriptions may be grouped together through the `add()`\n * method, which will attach a child Subscription to the current Subscription.\n * When a Subscription is unsubscribed, all its children (and its grandchildren)\n * will be unsubscribed as well.\n *\n * @class Subscription\n */\nexport class Subscription implements SubscriptionLike {\n /** @nocollapse */\n public static EMPTY = (() => {\n const empty = new Subscription();\n empty.closed = true;\n return empty;\n })();\n\n /**\n * A flag to indicate whether this Subscription has already been unsubscribed.\n */\n public closed = false;\n\n private _parentage: Subscription[] | Subscription | null = null;\n\n /**\n * The list of registered finalizers to execute upon unsubscription. Adding and removing from this\n * list occurs in the {@link #add} and {@link #remove} methods.\n */\n private _finalizers: Exclude[] | null = null;\n\n /**\n * @param initialTeardown A function executed first as part of the finalization\n * process that is kicked off when {@link #unsubscribe} is called.\n */\n constructor(private initialTeardown?: () => void) {}\n\n /**\n * Disposes the resources held by the subscription. May, for instance, cancel\n * an ongoing Observable execution or cancel any other type of work that\n * started when the Subscription was created.\n * @return {void}\n */\n unsubscribe(): void {\n let errors: any[] | undefined;\n\n if (!this.closed) {\n this.closed = true;\n\n // Remove this from it's parents.\n const { _parentage } = this;\n if (_parentage) {\n this._parentage = null;\n if (Array.isArray(_parentage)) {\n for (const parent of _parentage) {\n parent.remove(this);\n }\n } else {\n _parentage.remove(this);\n }\n }\n\n const { initialTeardown: initialFinalizer } = this;\n if (isFunction(initialFinalizer)) {\n try {\n initialFinalizer();\n } catch (e) {\n errors = e instanceof UnsubscriptionError ? e.errors : [e];\n }\n }\n\n const { _finalizers } = this;\n if (_finalizers) {\n this._finalizers = null;\n for (const finalizer of _finalizers) {\n try {\n execFinalizer(finalizer);\n } catch (err) {\n errors = errors ?? [];\n if (err instanceof UnsubscriptionError) {\n errors = [...errors, ...err.errors];\n } else {\n errors.push(err);\n }\n }\n }\n }\n\n if (errors) {\n throw new UnsubscriptionError(errors);\n }\n }\n }\n\n /**\n * Adds a finalizer to this subscription, so that finalization will be unsubscribed/called\n * when this subscription is unsubscribed. If this subscription is already {@link #closed},\n * because it has already been unsubscribed, then whatever finalizer is passed to it\n * will automatically be executed (unless the finalizer itself is also a closed subscription).\n *\n * Closed Subscriptions cannot be added as finalizers to any subscription. Adding a closed\n * subscription to a any subscription will result in no operation. (A noop).\n *\n * Adding a subscription to itself, or adding `null` or `undefined` will not perform any\n * operation at all. (A noop).\n *\n * `Subscription` instances that are added to this instance will automatically remove themselves\n * if they are unsubscribed. Functions and {@link Unsubscribable} objects that you wish to remove\n * will need to be removed manually with {@link #remove}\n *\n * @param teardown The finalization logic to add to this subscription.\n */\n add(teardown: TeardownLogic): void {\n // Only add the finalizer if it's not undefined\n // and don't add a subscription to itself.\n if (teardown && teardown !== this) {\n if (this.closed) {\n // If this subscription is already closed,\n // execute whatever finalizer is handed to it automatically.\n execFinalizer(teardown);\n } else {\n if (teardown instanceof Subscription) {\n // We don't add closed subscriptions, and we don't add the same subscription\n // twice. Subscription unsubscribe is idempotent.\n if (teardown.closed || teardown._hasParent(this)) {\n return;\n }\n teardown._addParent(this);\n }\n (this._finalizers = this._finalizers ?? []).push(teardown);\n }\n }\n }\n\n /**\n * Checks to see if a this subscription already has a particular parent.\n * This will signal that this subscription has already been added to the parent in question.\n * @param parent the parent to check for\n */\n private _hasParent(parent: Subscription) {\n const { _parentage } = this;\n return _parentage === parent || (Array.isArray(_parentage) && _parentage.includes(parent));\n }\n\n /**\n * Adds a parent to this subscription so it can be removed from the parent if it\n * unsubscribes on it's own.\n *\n * NOTE: THIS ASSUMES THAT {@link _hasParent} HAS ALREADY BEEN CHECKED.\n * @param parent The parent subscription to add\n */\n private _addParent(parent: Subscription) {\n const { _parentage } = this;\n this._parentage = Array.isArray(_parentage) ? (_parentage.push(parent), _parentage) : _parentage ? [_parentage, parent] : parent;\n }\n\n /**\n * Called on a child when it is removed via {@link #remove}.\n * @param parent The parent to remove\n */\n private _removeParent(parent: Subscription) {\n const { _parentage } = this;\n if (_parentage === parent) {\n this._parentage = null;\n } else if (Array.isArray(_parentage)) {\n arrRemove(_parentage, parent);\n }\n }\n\n /**\n * Removes a finalizer from this subscription that was previously added with the {@link #add} method.\n *\n * Note that `Subscription` instances, when unsubscribed, will automatically remove themselves\n * from every other `Subscription` they have been added to. This means that using the `remove` method\n * is not a common thing and should be used thoughtfully.\n *\n * If you add the same finalizer instance of a function or an unsubscribable object to a `Subscription` instance\n * more than once, you will need to call `remove` the same number of times to remove all instances.\n *\n * All finalizer instances are removed to free up memory upon unsubscription.\n *\n * @param teardown The finalizer to remove from this subscription\n */\n remove(teardown: Exclude): void {\n const { _finalizers } = this;\n _finalizers && arrRemove(_finalizers, teardown);\n\n if (teardown instanceof Subscription) {\n teardown._removeParent(this);\n }\n }\n}\n\nexport const EMPTY_SUBSCRIPTION = Subscription.EMPTY;\n\nexport function isSubscription(value: any): value is Subscription {\n return (\n value instanceof Subscription ||\n (value && 'closed' in value && isFunction(value.remove) && isFunction(value.add) && isFunction(value.unsubscribe))\n );\n}\n\nfunction execFinalizer(finalizer: Unsubscribable | (() => void)) {\n if (isFunction(finalizer)) {\n finalizer();\n } else {\n finalizer.unsubscribe();\n }\n}\n", "import { Subscriber } from './Subscriber';\nimport { ObservableNotification } from './types';\n\n/**\n * The {@link GlobalConfig} object for RxJS. It is used to configure things\n * like how to react on unhandled errors.\n */\nexport const config: GlobalConfig = {\n onUnhandledError: null,\n onStoppedNotification: null,\n Promise: undefined,\n useDeprecatedSynchronousErrorHandling: false,\n useDeprecatedNextContext: false,\n};\n\n/**\n * The global configuration object for RxJS, used to configure things\n * like how to react on unhandled errors. Accessible via {@link config}\n * object.\n */\nexport interface GlobalConfig {\n /**\n * A registration point for unhandled errors from RxJS. These are errors that\n * cannot were not handled by consuming code in the usual subscription path. For\n * example, if you have this configured, and you subscribe to an observable without\n * providing an error handler, errors from that subscription will end up here. This\n * will _always_ be called asynchronously on another job in the runtime. This is because\n * we do not want errors thrown in this user-configured handler to interfere with the\n * behavior of the library.\n */\n onUnhandledError: ((err: any) => void) | null;\n\n /**\n * A registration point for notifications that cannot be sent to subscribers because they\n * have completed, errored or have been explicitly unsubscribed. By default, next, complete\n * and error notifications sent to stopped subscribers are noops. However, sometimes callers\n * might want a different behavior. For example, with sources that attempt to report errors\n * to stopped subscribers, a caller can configure RxJS to throw an unhandled error instead.\n * This will _always_ be called asynchronously on another job in the runtime. This is because\n * we do not want errors thrown in this user-configured handler to interfere with the\n * behavior of the library.\n */\n onStoppedNotification: ((notification: ObservableNotification, subscriber: Subscriber) => void) | null;\n\n /**\n * The promise constructor used by default for {@link Observable#toPromise toPromise} and {@link Observable#forEach forEach}\n * methods.\n *\n * @deprecated As of version 8, RxJS will no longer support this sort of injection of a\n * Promise constructor. If you need a Promise implementation other than native promises,\n * please polyfill/patch Promise as you see appropriate. Will be removed in v8.\n */\n Promise?: PromiseConstructorLike;\n\n /**\n * If true, turns on synchronous error rethrowing, which is a deprecated behavior\n * in v6 and higher. This behavior enables bad patterns like wrapping a subscribe\n * call in a try/catch block. It also enables producer interference, a nasty bug\n * where a multicast can be broken for all observers by a downstream consumer with\n * an unhandled error. DO NOT USE THIS FLAG UNLESS IT'S NEEDED TO BUY TIME\n * FOR MIGRATION REASONS.\n *\n * @deprecated As of version 8, RxJS will no longer support synchronous throwing\n * of unhandled errors. All errors will be thrown on a separate call stack to prevent bad\n * behaviors described above. Will be removed in v8.\n */\n useDeprecatedSynchronousErrorHandling: boolean;\n\n /**\n * If true, enables an as-of-yet undocumented feature from v5: The ability to access\n * `unsubscribe()` via `this` context in `next` functions created in observers passed\n * to `subscribe`.\n *\n * This is being removed because the performance was severely problematic, and it could also cause\n * issues when types other than POJOs are passed to subscribe as subscribers, as they will likely have\n * their `this` context overwritten.\n *\n * @deprecated As of version 8, RxJS will no longer support altering the\n * context of next functions provided as part of an observer to Subscribe. Instead,\n * you will have access to a subscription or a signal or token that will allow you to do things like\n * unsubscribe and test closed status. Will be removed in v8.\n */\n useDeprecatedNextContext: boolean;\n}\n", "import type { TimerHandle } from './timerHandle';\ntype SetTimeoutFunction = (handler: () => void, timeout?: number, ...args: any[]) => TimerHandle;\ntype ClearTimeoutFunction = (handle: TimerHandle) => void;\n\ninterface TimeoutProvider {\n setTimeout: SetTimeoutFunction;\n clearTimeout: ClearTimeoutFunction;\n delegate:\n | {\n setTimeout: SetTimeoutFunction;\n clearTimeout: ClearTimeoutFunction;\n }\n | undefined;\n}\n\nexport const timeoutProvider: TimeoutProvider = {\n // When accessing the delegate, use the variable rather than `this` so that\n // the functions can be called without being bound to the provider.\n setTimeout(handler: () => void, timeout?: number, ...args) {\n const { delegate } = timeoutProvider;\n if (delegate?.setTimeout) {\n return delegate.setTimeout(handler, timeout, ...args);\n }\n return setTimeout(handler, timeout, ...args);\n },\n clearTimeout(handle) {\n const { delegate } = timeoutProvider;\n return (delegate?.clearTimeout || clearTimeout)(handle as any);\n },\n delegate: undefined,\n};\n", "import { config } from '../config';\nimport { timeoutProvider } from '../scheduler/timeoutProvider';\n\n/**\n * Handles an error on another job either with the user-configured {@link onUnhandledError},\n * or by throwing it on that new job so it can be picked up by `window.onerror`, `process.on('error')`, etc.\n *\n * This should be called whenever there is an error that is out-of-band with the subscription\n * or when an error hits a terminal boundary of the subscription and no error handler was provided.\n *\n * @param err the error to report\n */\nexport function reportUnhandledError(err: any) {\n timeoutProvider.setTimeout(() => {\n const { onUnhandledError } = config;\n if (onUnhandledError) {\n // Execute the user-configured error handler.\n onUnhandledError(err);\n } else {\n // Throw so it is picked up by the runtime's uncaught error mechanism.\n throw err;\n }\n });\n}\n", "/* tslint:disable:no-empty */\nexport function noop() { }\n", "import { CompleteNotification, NextNotification, ErrorNotification } from './types';\n\n/**\n * A completion object optimized for memory use and created to be the\n * same \"shape\" as other notifications in v8.\n * @internal\n */\nexport const COMPLETE_NOTIFICATION = (() => createNotification('C', undefined, undefined) as CompleteNotification)();\n\n/**\n * Internal use only. Creates an optimized error notification that is the same \"shape\"\n * as other notifications.\n * @internal\n */\nexport function errorNotification(error: any): ErrorNotification {\n return createNotification('E', undefined, error) as any;\n}\n\n/**\n * Internal use only. Creates an optimized next notification that is the same \"shape\"\n * as other notifications.\n * @internal\n */\nexport function nextNotification(value: T) {\n return createNotification('N', value, undefined) as NextNotification;\n}\n\n/**\n * Ensures that all notifications created internally have the same \"shape\" in v8.\n *\n * TODO: This is only exported to support a crazy legacy test in `groupBy`.\n * @internal\n */\nexport function createNotification(kind: 'N' | 'E' | 'C', value: any, error: any) {\n return {\n kind,\n value,\n error,\n };\n}\n", "import { config } from '../config';\n\nlet context: { errorThrown: boolean; error: any } | null = null;\n\n/**\n * Handles dealing with errors for super-gross mode. Creates a context, in which\n * any synchronously thrown errors will be passed to {@link captureError}. Which\n * will record the error such that it will be rethrown after the call back is complete.\n * TODO: Remove in v8\n * @param cb An immediately executed function.\n */\nexport function errorContext(cb: () => void) {\n if (config.useDeprecatedSynchronousErrorHandling) {\n const isRoot = !context;\n if (isRoot) {\n context = { errorThrown: false, error: null };\n }\n cb();\n if (isRoot) {\n const { errorThrown, error } = context!;\n context = null;\n if (errorThrown) {\n throw error;\n }\n }\n } else {\n // This is the general non-deprecated path for everyone that\n // isn't crazy enough to use super-gross mode (useDeprecatedSynchronousErrorHandling)\n cb();\n }\n}\n\n/**\n * Captures errors only in super-gross mode.\n * @param err the error to capture\n */\nexport function captureError(err: any) {\n if (config.useDeprecatedSynchronousErrorHandling && context) {\n context.errorThrown = true;\n context.error = err;\n }\n}\n", "import { isFunction } from './util/isFunction';\nimport { Observer, ObservableNotification } from './types';\nimport { isSubscription, Subscription } from './Subscription';\nimport { config } from './config';\nimport { reportUnhandledError } from './util/reportUnhandledError';\nimport { noop } from './util/noop';\nimport { nextNotification, errorNotification, COMPLETE_NOTIFICATION } from './NotificationFactories';\nimport { timeoutProvider } from './scheduler/timeoutProvider';\nimport { captureError } from './util/errorContext';\n\n/**\n * Implements the {@link Observer} interface and extends the\n * {@link Subscription} class. While the {@link Observer} is the public API for\n * consuming the values of an {@link Observable}, all Observers get converted to\n * a Subscriber, in order to provide Subscription-like capabilities such as\n * `unsubscribe`. Subscriber is a common type in RxJS, and crucial for\n * implementing operators, but it is rarely used as a public API.\n *\n * @class Subscriber\n */\nexport class Subscriber extends Subscription implements Observer {\n /**\n * A static factory for a Subscriber, given a (potentially partial) definition\n * of an Observer.\n * @param next The `next` callback of an Observer.\n * @param error The `error` callback of an\n * Observer.\n * @param complete The `complete` callback of an\n * Observer.\n * @return A Subscriber wrapping the (partially defined)\n * Observer represented by the given arguments.\n * @nocollapse\n * @deprecated Do not use. Will be removed in v8. There is no replacement for this\n * method, and there is no reason to be creating instances of `Subscriber` directly.\n * If you have a specific use case, please file an issue.\n */\n static create(next?: (x?: T) => void, error?: (e?: any) => void, complete?: () => void): Subscriber {\n return new SafeSubscriber(next, error, complete);\n }\n\n /** @deprecated Internal implementation detail, do not use directly. Will be made internal in v8. */\n protected isStopped: boolean = false;\n /** @deprecated Internal implementation detail, do not use directly. Will be made internal in v8. */\n protected destination: Subscriber | Observer; // this `any` is the escape hatch to erase extra type param (e.g. R)\n\n /**\n * @deprecated Internal implementation detail, do not use directly. Will be made internal in v8.\n * There is no reason to directly create an instance of Subscriber. This type is exported for typings reasons.\n */\n constructor(destination?: Subscriber | Observer) {\n super();\n if (destination) {\n this.destination = destination;\n // Automatically chain subscriptions together here.\n // if destination is a Subscription, then it is a Subscriber.\n if (isSubscription(destination)) {\n destination.add(this);\n }\n } else {\n this.destination = EMPTY_OBSERVER;\n }\n }\n\n /**\n * The {@link Observer} callback to receive notifications of type `next` from\n * the Observable, with a value. The Observable may call this method 0 or more\n * times.\n * @param {T} [value] The `next` value.\n * @return {void}\n */\n next(value?: T): void {\n if (this.isStopped) {\n handleStoppedNotification(nextNotification(value), this);\n } else {\n this._next(value!);\n }\n }\n\n /**\n * The {@link Observer} callback to receive notifications of type `error` from\n * the Observable, with an attached `Error`. Notifies the Observer that\n * the Observable has experienced an error condition.\n * @param {any} [err] The `error` exception.\n * @return {void}\n */\n error(err?: any): void {\n if (this.isStopped) {\n handleStoppedNotification(errorNotification(err), this);\n } else {\n this.isStopped = true;\n this._error(err);\n }\n }\n\n /**\n * The {@link Observer} callback to receive a valueless notification of type\n * `complete` from the Observable. Notifies the Observer that the Observable\n * has finished sending push-based notifications.\n * @return {void}\n */\n complete(): void {\n if (this.isStopped) {\n handleStoppedNotification(COMPLETE_NOTIFICATION, this);\n } else {\n this.isStopped = true;\n this._complete();\n }\n }\n\n unsubscribe(): void {\n if (!this.closed) {\n this.isStopped = true;\n super.unsubscribe();\n this.destination = null!;\n }\n }\n\n protected _next(value: T): void {\n this.destination.next(value);\n }\n\n protected _error(err: any): void {\n try {\n this.destination.error(err);\n } finally {\n this.unsubscribe();\n }\n }\n\n protected _complete(): void {\n try {\n this.destination.complete();\n } finally {\n this.unsubscribe();\n }\n }\n}\n\n/**\n * This bind is captured here because we want to be able to have\n * compatibility with monoid libraries that tend to use a method named\n * `bind`. In particular, a library called Monio requires this.\n */\nconst _bind = Function.prototype.bind;\n\nfunction bind any>(fn: Fn, thisArg: any): Fn {\n return _bind.call(fn, thisArg);\n}\n\n/**\n * Internal optimization only, DO NOT EXPOSE.\n * @internal\n */\nclass ConsumerObserver implements Observer {\n constructor(private partialObserver: Partial>) {}\n\n next(value: T): void {\n const { partialObserver } = this;\n if (partialObserver.next) {\n try {\n partialObserver.next(value);\n } catch (error) {\n handleUnhandledError(error);\n }\n }\n }\n\n error(err: any): void {\n const { partialObserver } = this;\n if (partialObserver.error) {\n try {\n partialObserver.error(err);\n } catch (error) {\n handleUnhandledError(error);\n }\n } else {\n handleUnhandledError(err);\n }\n }\n\n complete(): void {\n const { partialObserver } = this;\n if (partialObserver.complete) {\n try {\n partialObserver.complete();\n } catch (error) {\n handleUnhandledError(error);\n }\n }\n }\n}\n\nexport class SafeSubscriber extends Subscriber {\n constructor(\n observerOrNext?: Partial> | ((value: T) => void) | null,\n error?: ((e?: any) => void) | null,\n complete?: (() => void) | null\n ) {\n super();\n\n let partialObserver: Partial>;\n if (isFunction(observerOrNext) || !observerOrNext) {\n // The first argument is a function, not an observer. The next\n // two arguments *could* be observers, or they could be empty.\n partialObserver = {\n next: (observerOrNext ?? undefined) as (((value: T) => void) | undefined),\n error: error ?? undefined,\n complete: complete ?? undefined,\n };\n } else {\n // The first argument is a partial observer.\n let context: any;\n if (this && config.useDeprecatedNextContext) {\n // This is a deprecated path that made `this.unsubscribe()` available in\n // next handler functions passed to subscribe. This only exists behind a flag\n // now, as it is *very* slow.\n context = Object.create(observerOrNext);\n context.unsubscribe = () => this.unsubscribe();\n partialObserver = {\n next: observerOrNext.next && bind(observerOrNext.next, context),\n error: observerOrNext.error && bind(observerOrNext.error, context),\n complete: observerOrNext.complete && bind(observerOrNext.complete, context),\n };\n } else {\n // The \"normal\" path. Just use the partial observer directly.\n partialObserver = observerOrNext;\n }\n }\n\n // Wrap the partial observer to ensure it's a full observer, and\n // make sure proper error handling is accounted for.\n this.destination = new ConsumerObserver(partialObserver);\n }\n}\n\nfunction handleUnhandledError(error: any) {\n if (config.useDeprecatedSynchronousErrorHandling) {\n captureError(error);\n } else {\n // Ideal path, we report this as an unhandled error,\n // which is thrown on a new call stack.\n reportUnhandledError(error);\n }\n}\n\n/**\n * An error handler used when no error handler was supplied\n * to the SafeSubscriber -- meaning no error handler was supplied\n * do the `subscribe` call on our observable.\n * @param err The error to handle\n */\nfunction defaultErrorHandler(err: any) {\n throw err;\n}\n\n/**\n * A handler for notifications that cannot be sent to a stopped subscriber.\n * @param notification The notification being sent\n * @param subscriber The stopped subscriber\n */\nfunction handleStoppedNotification(notification: ObservableNotification, subscriber: Subscriber) {\n const { onStoppedNotification } = config;\n onStoppedNotification && timeoutProvider.setTimeout(() => onStoppedNotification(notification, subscriber));\n}\n\n/**\n * The observer used as a stub for subscriptions where the user did not\n * pass any arguments to `subscribe`. Comes with the default error handling\n * behavior.\n */\nexport const EMPTY_OBSERVER: Readonly> & { closed: true } = {\n closed: true,\n next: noop,\n error: defaultErrorHandler,\n complete: noop,\n};\n", "/**\n * Symbol.observable or a string \"@@observable\". Used for interop\n *\n * @deprecated We will no longer be exporting this symbol in upcoming versions of RxJS.\n * Instead polyfill and use Symbol.observable directly *or* use https://www.npmjs.com/package/symbol-observable\n */\nexport const observable: string | symbol = (() => (typeof Symbol === 'function' && Symbol.observable) || '@@observable')();\n", "/**\n * This function takes one parameter and just returns it. Simply put,\n * this is like `(x: T): T => x`.\n *\n * ## Examples\n *\n * This is useful in some cases when using things like `mergeMap`\n *\n * ```ts\n * import { interval, take, map, range, mergeMap, identity } from 'rxjs';\n *\n * const source$ = interval(1000).pipe(take(5));\n *\n * const result$ = source$.pipe(\n * map(i => range(i)),\n * mergeMap(identity) // same as mergeMap(x => x)\n * );\n *\n * result$.subscribe({\n * next: console.log\n * });\n * ```\n *\n * Or when you want to selectively apply an operator\n *\n * ```ts\n * import { interval, take, identity } from 'rxjs';\n *\n * const shouldLimit = () => Math.random() < 0.5;\n *\n * const source$ = interval(1000);\n *\n * const result$ = source$.pipe(shouldLimit() ? take(5) : identity);\n *\n * result$.subscribe({\n * next: console.log\n * });\n * ```\n *\n * @param x Any value that is returned by this function\n * @returns The value passed as the first parameter to this function\n */\nexport function identity(x: T): T {\n return x;\n}\n", "import { identity } from './identity';\nimport { UnaryFunction } from '../types';\n\nexport function pipe(): typeof identity;\nexport function pipe(fn1: UnaryFunction): UnaryFunction;\nexport function pipe(fn1: UnaryFunction, fn2: UnaryFunction): UnaryFunction;\nexport function pipe(fn1: UnaryFunction, fn2: UnaryFunction, fn3: UnaryFunction): UnaryFunction;\nexport function pipe(\n fn1: UnaryFunction,\n fn2: UnaryFunction,\n fn3: UnaryFunction,\n fn4: UnaryFunction\n): UnaryFunction;\nexport function pipe(\n fn1: UnaryFunction,\n fn2: UnaryFunction,\n fn3: UnaryFunction,\n fn4: UnaryFunction,\n fn5: UnaryFunction\n): UnaryFunction;\nexport function pipe(\n fn1: UnaryFunction,\n fn2: UnaryFunction,\n fn3: UnaryFunction,\n fn4: UnaryFunction,\n fn5: UnaryFunction,\n fn6: UnaryFunction\n): UnaryFunction;\nexport function pipe(\n fn1: UnaryFunction,\n fn2: UnaryFunction,\n fn3: UnaryFunction,\n fn4: UnaryFunction,\n fn5: UnaryFunction,\n fn6: UnaryFunction,\n fn7: UnaryFunction\n): UnaryFunction;\nexport function pipe(\n fn1: UnaryFunction,\n fn2: UnaryFunction,\n fn3: UnaryFunction,\n fn4: UnaryFunction,\n fn5: UnaryFunction,\n fn6: UnaryFunction,\n fn7: UnaryFunction,\n fn8: UnaryFunction\n): UnaryFunction;\nexport function pipe(\n fn1: UnaryFunction,\n fn2: UnaryFunction,\n fn3: UnaryFunction,\n fn4: UnaryFunction,\n fn5: UnaryFunction,\n fn6: UnaryFunction,\n fn7: UnaryFunction,\n fn8: UnaryFunction,\n fn9: UnaryFunction\n): UnaryFunction;\nexport function pipe(\n fn1: UnaryFunction,\n fn2: UnaryFunction,\n fn3: UnaryFunction,\n fn4: UnaryFunction,\n fn5: UnaryFunction,\n fn6: UnaryFunction,\n fn7: UnaryFunction,\n fn8: UnaryFunction,\n fn9: UnaryFunction,\n ...fns: UnaryFunction[]\n): UnaryFunction;\n\n/**\n * pipe() can be called on one or more functions, each of which can take one argument (\"UnaryFunction\")\n * and uses it to return a value.\n * It returns a function that takes one argument, passes it to the first UnaryFunction, and then\n * passes the result to the next one, passes that result to the next one, and so on. \n */\nexport function pipe(...fns: Array>): UnaryFunction {\n return pipeFromArray(fns);\n}\n\n/** @internal */\nexport function pipeFromArray(fns: Array>): UnaryFunction {\n if (fns.length === 0) {\n return identity as UnaryFunction;\n }\n\n if (fns.length === 1) {\n return fns[0];\n }\n\n return function piped(input: T): R {\n return fns.reduce((prev: any, fn: UnaryFunction) => fn(prev), input as any);\n };\n}\n", "import { Operator } from './Operator';\nimport { SafeSubscriber, Subscriber } from './Subscriber';\nimport { isSubscription, Subscription } from './Subscription';\nimport { TeardownLogic, OperatorFunction, Subscribable, Observer } from './types';\nimport { observable as Symbol_observable } from './symbol/observable';\nimport { pipeFromArray } from './util/pipe';\nimport { config } from './config';\nimport { isFunction } from './util/isFunction';\nimport { errorContext } from './util/errorContext';\n\n/**\n * A representation of any set of values over any amount of time. This is the most basic building block\n * of RxJS.\n *\n * @class Observable\n */\nexport class Observable implements Subscribable {\n /**\n * @deprecated Internal implementation detail, do not use directly. Will be made internal in v8.\n */\n source: Observable | undefined;\n\n /**\n * @deprecated Internal implementation detail, do not use directly. Will be made internal in v8.\n */\n operator: Operator | undefined;\n\n /**\n * @constructor\n * @param {Function} subscribe the function that is called when the Observable is\n * initially subscribed to. This function is given a Subscriber, to which new values\n * can be `next`ed, or an `error` method can be called to raise an error, or\n * `complete` can be called to notify of a successful completion.\n */\n constructor(subscribe?: (this: Observable, subscriber: Subscriber) => TeardownLogic) {\n if (subscribe) {\n this._subscribe = subscribe;\n }\n }\n\n // HACK: Since TypeScript inherits static properties too, we have to\n // fight against TypeScript here so Subject can have a different static create signature\n /**\n * Creates a new Observable by calling the Observable constructor\n * @owner Observable\n * @method create\n * @param {Function} subscribe? the subscriber function to be passed to the Observable constructor\n * @return {Observable} a new observable\n * @nocollapse\n * @deprecated Use `new Observable()` instead. Will be removed in v8.\n */\n static create: (...args: any[]) => any = (subscribe?: (subscriber: Subscriber) => TeardownLogic) => {\n return new Observable(subscribe);\n };\n\n /**\n * Creates a new Observable, with this Observable instance as the source, and the passed\n * operator defined as the new observable's operator.\n * @method lift\n * @param operator the operator defining the operation to take on the observable\n * @return a new observable with the Operator applied\n * @deprecated Internal implementation detail, do not use directly. Will be made internal in v8.\n * If you have implemented an operator using `lift`, it is recommended that you create an\n * operator by simply returning `new Observable()` directly. See \"Creating new operators from\n * scratch\" section here: https://rxjs.dev/guide/operators\n */\n lift(operator?: Operator): Observable {\n const observable = new Observable();\n observable.source = this;\n observable.operator = operator;\n return observable;\n }\n\n subscribe(observerOrNext?: Partial> | ((value: T) => void)): Subscription;\n /** @deprecated Instead of passing separate callback arguments, use an observer argument. Signatures taking separate callback arguments will be removed in v8. Details: https://rxjs.dev/deprecations/subscribe-arguments */\n subscribe(next?: ((value: T) => void) | null, error?: ((error: any) => void) | null, complete?: (() => void) | null): Subscription;\n /**\n * Invokes an execution of an Observable and registers Observer handlers for notifications it will emit.\n *\n * Use it when you have all these Observables, but still nothing is happening.\n *\n * `subscribe` is not a regular operator, but a method that calls Observable's internal `subscribe` function. It\n * might be for example a function that you passed to Observable's constructor, but most of the time it is\n * a library implementation, which defines what will be emitted by an Observable, and when it be will emitted. This means\n * that calling `subscribe` is actually the moment when Observable starts its work, not when it is created, as it is often\n * the thought.\n *\n * Apart from starting the execution of an Observable, this method allows you to listen for values\n * that an Observable emits, as well as for when it completes or errors. You can achieve this in two\n * of the following ways.\n *\n * The first way is creating an object that implements {@link Observer} interface. It should have methods\n * defined by that interface, but note that it should be just a regular JavaScript object, which you can create\n * yourself in any way you want (ES6 class, classic function constructor, object literal etc.). In particular, do\n * not attempt to use any RxJS implementation details to create Observers - you don't need them. Remember also\n * that your object does not have to implement all methods. If you find yourself creating a method that doesn't\n * do anything, you can simply omit it. Note however, if the `error` method is not provided and an error happens,\n * it will be thrown asynchronously. Errors thrown asynchronously cannot be caught using `try`/`catch`. Instead,\n * use the {@link onUnhandledError} configuration option or use a runtime handler (like `window.onerror` or\n * `process.on('error)`) to be notified of unhandled errors. Because of this, it's recommended that you provide\n * an `error` method to avoid missing thrown errors.\n *\n * The second way is to give up on Observer object altogether and simply provide callback functions in place of its methods.\n * This means you can provide three functions as arguments to `subscribe`, where the first function is equivalent\n * of a `next` method, the second of an `error` method and the third of a `complete` method. Just as in case of an Observer,\n * if you do not need to listen for something, you can omit a function by passing `undefined` or `null`,\n * since `subscribe` recognizes these functions by where they were placed in function call. When it comes\n * to the `error` function, as with an Observer, if not provided, errors emitted by an Observable will be thrown asynchronously.\n *\n * You can, however, subscribe with no parameters at all. This may be the case where you're not interested in terminal events\n * and you also handled emissions internally by using operators (e.g. using `tap`).\n *\n * Whichever style of calling `subscribe` you use, in both cases it returns a Subscription object.\n * This object allows you to call `unsubscribe` on it, which in turn will stop the work that an Observable does and will clean\n * up all resources that an Observable used. Note that cancelling a subscription will not call `complete` callback\n * provided to `subscribe` function, which is reserved for a regular completion signal that comes from an Observable.\n *\n * Remember that callbacks provided to `subscribe` are not guaranteed to be called asynchronously.\n * It is an Observable itself that decides when these functions will be called. For example {@link of}\n * by default emits all its values synchronously. Always check documentation for how given Observable\n * will behave when subscribed and if its default behavior can be modified with a `scheduler`.\n *\n * #### Examples\n *\n * Subscribe with an {@link guide/observer Observer}\n *\n * ```ts\n * import { of } from 'rxjs';\n *\n * const sumObserver = {\n * sum: 0,\n * next(value) {\n * console.log('Adding: ' + value);\n * this.sum = this.sum + value;\n * },\n * error() {\n * // We actually could just remove this method,\n * // since we do not really care about errors right now.\n * },\n * complete() {\n * console.log('Sum equals: ' + this.sum);\n * }\n * };\n *\n * of(1, 2, 3) // Synchronously emits 1, 2, 3 and then completes.\n * .subscribe(sumObserver);\n *\n * // Logs:\n * // 'Adding: 1'\n * // 'Adding: 2'\n * // 'Adding: 3'\n * // 'Sum equals: 6'\n * ```\n *\n * Subscribe with functions ({@link deprecations/subscribe-arguments deprecated})\n *\n * ```ts\n * import { of } from 'rxjs'\n *\n * let sum = 0;\n *\n * of(1, 2, 3).subscribe(\n * value => {\n * console.log('Adding: ' + value);\n * sum = sum + value;\n * },\n * undefined,\n * () => console.log('Sum equals: ' + sum)\n * );\n *\n * // Logs:\n * // 'Adding: 1'\n * // 'Adding: 2'\n * // 'Adding: 3'\n * // 'Sum equals: 6'\n * ```\n *\n * Cancel a subscription\n *\n * ```ts\n * import { interval } from 'rxjs';\n *\n * const subscription = interval(1000).subscribe({\n * next(num) {\n * console.log(num)\n * },\n * complete() {\n * // Will not be called, even when cancelling subscription.\n * console.log('completed!');\n * }\n * });\n *\n * setTimeout(() => {\n * subscription.unsubscribe();\n * console.log('unsubscribed!');\n * }, 2500);\n *\n * // Logs:\n * // 0 after 1s\n * // 1 after 2s\n * // 'unsubscribed!' after 2.5s\n * ```\n *\n * @param {Observer|Function} observerOrNext (optional) Either an observer with methods to be called,\n * or the first of three possible handlers, which is the handler for each value emitted from the subscribed\n * Observable.\n * @param {Function} error (optional) A handler for a terminal event resulting from an error. If no error handler is provided,\n * the error will be thrown asynchronously as unhandled.\n * @param {Function} complete (optional) A handler for a terminal event resulting from successful completion.\n * @return {Subscription} a subscription reference to the registered handlers\n * @method subscribe\n */\n subscribe(\n observerOrNext?: Partial> | ((value: T) => void) | null,\n error?: ((error: any) => void) | null,\n complete?: (() => void) | null\n ): Subscription {\n const subscriber = isSubscriber(observerOrNext) ? observerOrNext : new SafeSubscriber(observerOrNext, error, complete);\n\n errorContext(() => {\n const { operator, source } = this;\n subscriber.add(\n operator\n ? // We're dealing with a subscription in the\n // operator chain to one of our lifted operators.\n operator.call(subscriber, source)\n : source\n ? // If `source` has a value, but `operator` does not, something that\n // had intimate knowledge of our API, like our `Subject`, must have\n // set it. We're going to just call `_subscribe` directly.\n this._subscribe(subscriber)\n : // In all other cases, we're likely wrapping a user-provided initializer\n // function, so we need to catch errors and handle them appropriately.\n this._trySubscribe(subscriber)\n );\n });\n\n return subscriber;\n }\n\n /** @internal */\n protected _trySubscribe(sink: Subscriber): TeardownLogic {\n try {\n return this._subscribe(sink);\n } catch (err) {\n // We don't need to return anything in this case,\n // because it's just going to try to `add()` to a subscription\n // above.\n sink.error(err);\n }\n }\n\n /**\n * Used as a NON-CANCELLABLE means of subscribing to an observable, for use with\n * APIs that expect promises, like `async/await`. You cannot unsubscribe from this.\n *\n * **WARNING**: Only use this with observables you *know* will complete. If the source\n * observable does not complete, you will end up with a promise that is hung up, and\n * potentially all of the state of an async function hanging out in memory. To avoid\n * this situation, look into adding something like {@link timeout}, {@link take},\n * {@link takeWhile}, or {@link takeUntil} amongst others.\n *\n * #### Example\n *\n * ```ts\n * import { interval, take } from 'rxjs';\n *\n * const source$ = interval(1000).pipe(take(4));\n *\n * async function getTotal() {\n * let total = 0;\n *\n * await source$.forEach(value => {\n * total += value;\n * console.log('observable -> ' + value);\n * });\n *\n * return total;\n * }\n *\n * getTotal().then(\n * total => console.log('Total: ' + total)\n * );\n *\n * // Expected:\n * // 'observable -> 0'\n * // 'observable -> 1'\n * // 'observable -> 2'\n * // 'observable -> 3'\n * // 'Total: 6'\n * ```\n *\n * @param next a handler for each value emitted by the observable\n * @return a promise that either resolves on observable completion or\n * rejects with the handled error\n */\n forEach(next: (value: T) => void): Promise;\n\n /**\n * @param next a handler for each value emitted by the observable\n * @param promiseCtor a constructor function used to instantiate the Promise\n * @return a promise that either resolves on observable completion or\n * rejects with the handled error\n * @deprecated Passing a Promise constructor will no longer be available\n * in upcoming versions of RxJS. This is because it adds weight to the library, for very\n * little benefit. If you need this functionality, it is recommended that you either\n * polyfill Promise, or you create an adapter to convert the returned native promise\n * to whatever promise implementation you wanted. Will be removed in v8.\n */\n forEach(next: (value: T) => void, promiseCtor: PromiseConstructorLike): Promise;\n\n forEach(next: (value: T) => void, promiseCtor?: PromiseConstructorLike): Promise {\n promiseCtor = getPromiseCtor(promiseCtor);\n\n return new promiseCtor((resolve, reject) => {\n const subscriber = new SafeSubscriber({\n next: (value) => {\n try {\n next(value);\n } catch (err) {\n reject(err);\n subscriber.unsubscribe();\n }\n },\n error: reject,\n complete: resolve,\n });\n this.subscribe(subscriber);\n }) as Promise;\n }\n\n /** @internal */\n protected _subscribe(subscriber: Subscriber): TeardownLogic {\n return this.source?.subscribe(subscriber);\n }\n\n /**\n * An interop point defined by the es7-observable spec https://github.com/zenparsing/es-observable\n * @method Symbol.observable\n * @return {Observable} this instance of the observable\n */\n [Symbol_observable]() {\n return this;\n }\n\n /* tslint:disable:max-line-length */\n pipe(): Observable;\n pipe(op1: OperatorFunction): Observable;\n pipe(op1: OperatorFunction, op2: OperatorFunction): Observable;\n pipe(op1: OperatorFunction, op2: OperatorFunction, op3: OperatorFunction): Observable;\n pipe(\n op1: OperatorFunction,\n op2: OperatorFunction,\n op3: OperatorFunction,\n op4: OperatorFunction\n ): Observable;\n pipe(\n op1: OperatorFunction,\n op2: OperatorFunction,\n op3: OperatorFunction,\n op4: OperatorFunction,\n op5: OperatorFunction\n ): Observable;\n pipe(\n op1: OperatorFunction,\n op2: OperatorFunction,\n op3: OperatorFunction,\n op4: OperatorFunction,\n op5: OperatorFunction,\n op6: OperatorFunction\n ): Observable;\n pipe(\n op1: OperatorFunction,\n op2: OperatorFunction,\n op3: OperatorFunction,\n op4: OperatorFunction,\n op5: OperatorFunction,\n op6: OperatorFunction,\n op7: OperatorFunction\n ): Observable;\n pipe(\n op1: OperatorFunction,\n op2: OperatorFunction,\n op3: OperatorFunction,\n op4: OperatorFunction,\n op5: OperatorFunction,\n op6: OperatorFunction,\n op7: OperatorFunction,\n op8: OperatorFunction\n ): Observable;\n pipe(\n op1: OperatorFunction,\n op2: OperatorFunction,\n op3: OperatorFunction,\n op4: OperatorFunction,\n op5: OperatorFunction,\n op6: OperatorFunction,\n op7: OperatorFunction,\n op8: OperatorFunction,\n op9: OperatorFunction\n ): Observable;\n pipe(\n op1: OperatorFunction,\n op2: OperatorFunction,\n op3: OperatorFunction,\n op4: OperatorFunction,\n op5: OperatorFunction,\n op6: OperatorFunction,\n op7: OperatorFunction,\n op8: OperatorFunction,\n op9: OperatorFunction,\n ...operations: OperatorFunction[]\n ): Observable;\n /* tslint:enable:max-line-length */\n\n /**\n * Used to stitch together functional operators into a chain.\n * @method pipe\n * @return {Observable} the Observable result of all of the operators having\n * been called in the order they were passed in.\n *\n * ## Example\n *\n * ```ts\n * import { interval, filter, map, scan } from 'rxjs';\n *\n * interval(1000)\n * .pipe(\n * filter(x => x % 2 === 0),\n * map(x => x + x),\n * scan((acc, x) => acc + x)\n * )\n * .subscribe(x => console.log(x));\n * ```\n */\n pipe(...operations: OperatorFunction[]): Observable {\n return pipeFromArray(operations)(this);\n }\n\n /* tslint:disable:max-line-length */\n /** @deprecated Replaced with {@link firstValueFrom} and {@link lastValueFrom}. Will be removed in v8. Details: https://rxjs.dev/deprecations/to-promise */\n toPromise(): Promise;\n /** @deprecated Replaced with {@link firstValueFrom} and {@link lastValueFrom}. Will be removed in v8. Details: https://rxjs.dev/deprecations/to-promise */\n toPromise(PromiseCtor: typeof Promise): Promise;\n /** @deprecated Replaced with {@link firstValueFrom} and {@link lastValueFrom}. Will be removed in v8. Details: https://rxjs.dev/deprecations/to-promise */\n toPromise(PromiseCtor: PromiseConstructorLike): Promise;\n /* tslint:enable:max-line-length */\n\n /**\n * Subscribe to this Observable and get a Promise resolving on\n * `complete` with the last emission (if any).\n *\n * **WARNING**: Only use this with observables you *know* will complete. If the source\n * observable does not complete, you will end up with a promise that is hung up, and\n * potentially all of the state of an async function hanging out in memory. To avoid\n * this situation, look into adding something like {@link timeout}, {@link take},\n * {@link takeWhile}, or {@link takeUntil} amongst others.\n *\n * @method toPromise\n * @param [promiseCtor] a constructor function used to instantiate\n * the Promise\n * @return A Promise that resolves with the last value emit, or\n * rejects on an error. If there were no emissions, Promise\n * resolves with undefined.\n * @deprecated Replaced with {@link firstValueFrom} and {@link lastValueFrom}. Will be removed in v8. Details: https://rxjs.dev/deprecations/to-promise\n */\n toPromise(promiseCtor?: PromiseConstructorLike): Promise {\n promiseCtor = getPromiseCtor(promiseCtor);\n\n return new promiseCtor((resolve, reject) => {\n let value: T | undefined;\n this.subscribe(\n (x: T) => (value = x),\n (err: any) => reject(err),\n () => resolve(value)\n );\n }) as Promise;\n }\n}\n\n/**\n * Decides between a passed promise constructor from consuming code,\n * A default configured promise constructor, and the native promise\n * constructor and returns it. If nothing can be found, it will throw\n * an error.\n * @param promiseCtor The optional promise constructor to passed by consuming code\n */\nfunction getPromiseCtor(promiseCtor: PromiseConstructorLike | undefined) {\n return promiseCtor ?? config.Promise ?? Promise;\n}\n\nfunction isObserver(value: any): value is Observer {\n return value && isFunction(value.next) && isFunction(value.error) && isFunction(value.complete);\n}\n\nfunction isSubscriber(value: any): value is Subscriber {\n return (value && value instanceof Subscriber) || (isObserver(value) && isSubscription(value));\n}\n", "import { Observable } from '../Observable';\nimport { Subscriber } from '../Subscriber';\nimport { OperatorFunction } from '../types';\nimport { isFunction } from './isFunction';\n\n/**\n * Used to determine if an object is an Observable with a lift function.\n */\nexport function hasLift(source: any): source is { lift: InstanceType['lift'] } {\n return isFunction(source?.lift);\n}\n\n/**\n * Creates an `OperatorFunction`. Used to define operators throughout the library in a concise way.\n * @param init The logic to connect the liftedSource to the subscriber at the moment of subscription.\n */\nexport function operate(\n init: (liftedSource: Observable, subscriber: Subscriber) => (() => void) | void\n): OperatorFunction {\n return (source: Observable) => {\n if (hasLift(source)) {\n return source.lift(function (this: Subscriber, liftedSource: Observable) {\n try {\n return init(liftedSource, this);\n } catch (err) {\n this.error(err);\n }\n });\n }\n throw new TypeError('Unable to lift unknown Observable type');\n };\n}\n", "import { Subscriber } from '../Subscriber';\n\n/**\n * Creates an instance of an `OperatorSubscriber`.\n * @param destination The downstream subscriber.\n * @param onNext Handles next values, only called if this subscriber is not stopped or closed. Any\n * error that occurs in this function is caught and sent to the `error` method of this subscriber.\n * @param onError Handles errors from the subscription, any errors that occur in this handler are caught\n * and send to the `destination` error handler.\n * @param onComplete Handles completion notification from the subscription. Any errors that occur in\n * this handler are sent to the `destination` error handler.\n * @param onFinalize Additional teardown logic here. This will only be called on teardown if the\n * subscriber itself is not already closed. This is called after all other teardown logic is executed.\n */\nexport function createOperatorSubscriber(\n destination: Subscriber,\n onNext?: (value: T) => void,\n onComplete?: () => void,\n onError?: (err: any) => void,\n onFinalize?: () => void\n): Subscriber {\n return new OperatorSubscriber(destination, onNext, onComplete, onError, onFinalize);\n}\n\n/**\n * A generic helper for allowing operators to be created with a Subscriber and\n * use closures to capture necessary state from the operator function itself.\n */\nexport class OperatorSubscriber extends Subscriber {\n /**\n * Creates an instance of an `OperatorSubscriber`.\n * @param destination The downstream subscriber.\n * @param onNext Handles next values, only called if this subscriber is not stopped or closed. Any\n * error that occurs in this function is caught and sent to the `error` method of this subscriber.\n * @param onError Handles errors from the subscription, any errors that occur in this handler are caught\n * and send to the `destination` error handler.\n * @param onComplete Handles completion notification from the subscription. Any errors that occur in\n * this handler are sent to the `destination` error handler.\n * @param onFinalize Additional finalization logic here. This will only be called on finalization if the\n * subscriber itself is not already closed. This is called after all other finalization logic is executed.\n * @param shouldUnsubscribe An optional check to see if an unsubscribe call should truly unsubscribe.\n * NOTE: This currently **ONLY** exists to support the strange behavior of {@link groupBy}, where unsubscription\n * to the resulting observable does not actually disconnect from the source if there are active subscriptions\n * to any grouped observable. (DO NOT EXPOSE OR USE EXTERNALLY!!!)\n */\n constructor(\n destination: Subscriber,\n onNext?: (value: T) => void,\n onComplete?: () => void,\n onError?: (err: any) => void,\n private onFinalize?: () => void,\n private shouldUnsubscribe?: () => boolean\n ) {\n // It's important - for performance reasons - that all of this class's\n // members are initialized and that they are always initialized in the same\n // order. This will ensure that all OperatorSubscriber instances have the\n // same hidden class in V8. This, in turn, will help keep the number of\n // hidden classes involved in property accesses within the base class as\n // low as possible. If the number of hidden classes involved exceeds four,\n // the property accesses will become megamorphic and performance penalties\n // will be incurred - i.e. inline caches won't be used.\n //\n // The reasons for ensuring all instances have the same hidden class are\n // further discussed in this blog post from Benedikt Meurer:\n // https://benediktmeurer.de/2018/03/23/impact-of-polymorphism-on-component-based-frameworks-like-react/\n super(destination);\n this._next = onNext\n ? function (this: OperatorSubscriber, value: T) {\n try {\n onNext(value);\n } catch (err) {\n destination.error(err);\n }\n }\n : super._next;\n this._error = onError\n ? function (this: OperatorSubscriber, err: any) {\n try {\n onError(err);\n } catch (err) {\n // Send any errors that occur down stream.\n destination.error(err);\n } finally {\n // Ensure finalization.\n this.unsubscribe();\n }\n }\n : super._error;\n this._complete = onComplete\n ? function (this: OperatorSubscriber) {\n try {\n onComplete();\n } catch (err) {\n // Send any errors that occur down stream.\n destination.error(err);\n } finally {\n // Ensure finalization.\n this.unsubscribe();\n }\n }\n : super._complete;\n }\n\n unsubscribe() {\n if (!this.shouldUnsubscribe || this.shouldUnsubscribe()) {\n const { closed } = this;\n super.unsubscribe();\n // Execute additional teardown if we have any and we didn't already do so.\n !closed && this.onFinalize?.();\n }\n }\n}\n", "import { Subscription } from '../Subscription';\n\ninterface AnimationFrameProvider {\n schedule(callback: FrameRequestCallback): Subscription;\n requestAnimationFrame: typeof requestAnimationFrame;\n cancelAnimationFrame: typeof cancelAnimationFrame;\n delegate:\n | {\n requestAnimationFrame: typeof requestAnimationFrame;\n cancelAnimationFrame: typeof cancelAnimationFrame;\n }\n | undefined;\n}\n\nexport const animationFrameProvider: AnimationFrameProvider = {\n // When accessing the delegate, use the variable rather than `this` so that\n // the functions can be called without being bound to the provider.\n schedule(callback) {\n let request = requestAnimationFrame;\n let cancel: typeof cancelAnimationFrame | undefined = cancelAnimationFrame;\n const { delegate } = animationFrameProvider;\n if (delegate) {\n request = delegate.requestAnimationFrame;\n cancel = delegate.cancelAnimationFrame;\n }\n const handle = request((timestamp) => {\n // Clear the cancel function. The request has been fulfilled, so\n // attempting to cancel the request upon unsubscription would be\n // pointless.\n cancel = undefined;\n callback(timestamp);\n });\n return new Subscription(() => cancel?.(handle));\n },\n requestAnimationFrame(...args) {\n const { delegate } = animationFrameProvider;\n return (delegate?.requestAnimationFrame || requestAnimationFrame)(...args);\n },\n cancelAnimationFrame(...args) {\n const { delegate } = animationFrameProvider;\n return (delegate?.cancelAnimationFrame || cancelAnimationFrame)(...args);\n },\n delegate: undefined,\n};\n", "import { createErrorClass } from './createErrorClass';\n\nexport interface ObjectUnsubscribedError extends Error {}\n\nexport interface ObjectUnsubscribedErrorCtor {\n /**\n * @deprecated Internal implementation detail. Do not construct error instances.\n * Cannot be tagged as internal: https://github.com/ReactiveX/rxjs/issues/6269\n */\n new (): ObjectUnsubscribedError;\n}\n\n/**\n * An error thrown when an action is invalid because the object has been\n * unsubscribed.\n *\n * @see {@link Subject}\n * @see {@link BehaviorSubject}\n *\n * @class ObjectUnsubscribedError\n */\nexport const ObjectUnsubscribedError: ObjectUnsubscribedErrorCtor = createErrorClass(\n (_super) =>\n function ObjectUnsubscribedErrorImpl(this: any) {\n _super(this);\n this.name = 'ObjectUnsubscribedError';\n this.message = 'object unsubscribed';\n }\n);\n", "import { Operator } from './Operator';\nimport { Observable } from './Observable';\nimport { Subscriber } from './Subscriber';\nimport { Subscription, EMPTY_SUBSCRIPTION } from './Subscription';\nimport { Observer, SubscriptionLike, TeardownLogic } from './types';\nimport { ObjectUnsubscribedError } from './util/ObjectUnsubscribedError';\nimport { arrRemove } from './util/arrRemove';\nimport { errorContext } from './util/errorContext';\n\n/**\n * A Subject is a special type of Observable that allows values to be\n * multicasted to many Observers. Subjects are like EventEmitters.\n *\n * Every Subject is an Observable and an Observer. You can subscribe to a\n * Subject, and you can call next to feed values as well as error and complete.\n */\nexport class Subject extends Observable implements SubscriptionLike {\n closed = false;\n\n private currentObservers: Observer[] | null = null;\n\n /** @deprecated Internal implementation detail, do not use directly. Will be made internal in v8. */\n observers: Observer[] = [];\n /** @deprecated Internal implementation detail, do not use directly. Will be made internal in v8. */\n isStopped = false;\n /** @deprecated Internal implementation detail, do not use directly. Will be made internal in v8. */\n hasError = false;\n /** @deprecated Internal implementation detail, do not use directly. Will be made internal in v8. */\n thrownError: any = null;\n\n /**\n * Creates a \"subject\" by basically gluing an observer to an observable.\n *\n * @nocollapse\n * @deprecated Recommended you do not use. Will be removed at some point in the future. Plans for replacement still under discussion.\n */\n static create: (...args: any[]) => any = (destination: Observer, source: Observable): AnonymousSubject => {\n return new AnonymousSubject(destination, source);\n };\n\n constructor() {\n // NOTE: This must be here to obscure Observable's constructor.\n super();\n }\n\n /** @deprecated Internal implementation detail, do not use directly. Will be made internal in v8. */\n lift(operator: Operator): Observable {\n const subject = new AnonymousSubject(this, this);\n subject.operator = operator as any;\n return subject as any;\n }\n\n /** @internal */\n protected _throwIfClosed() {\n if (this.closed) {\n throw new ObjectUnsubscribedError();\n }\n }\n\n next(value: T) {\n errorContext(() => {\n this._throwIfClosed();\n if (!this.isStopped) {\n if (!this.currentObservers) {\n this.currentObservers = Array.from(this.observers);\n }\n for (const observer of this.currentObservers) {\n observer.next(value);\n }\n }\n });\n }\n\n error(err: any) {\n errorContext(() => {\n this._throwIfClosed();\n if (!this.isStopped) {\n this.hasError = this.isStopped = true;\n this.thrownError = err;\n const { observers } = this;\n while (observers.length) {\n observers.shift()!.error(err);\n }\n }\n });\n }\n\n complete() {\n errorContext(() => {\n this._throwIfClosed();\n if (!this.isStopped) {\n this.isStopped = true;\n const { observers } = this;\n while (observers.length) {\n observers.shift()!.complete();\n }\n }\n });\n }\n\n unsubscribe() {\n this.isStopped = this.closed = true;\n this.observers = this.currentObservers = null!;\n }\n\n get observed() {\n return this.observers?.length > 0;\n }\n\n /** @internal */\n protected _trySubscribe(subscriber: Subscriber): TeardownLogic {\n this._throwIfClosed();\n return super._trySubscribe(subscriber);\n }\n\n /** @internal */\n protected _subscribe(subscriber: Subscriber): Subscription {\n this._throwIfClosed();\n this._checkFinalizedStatuses(subscriber);\n return this._innerSubscribe(subscriber);\n }\n\n /** @internal */\n protected _innerSubscribe(subscriber: Subscriber) {\n const { hasError, isStopped, observers } = this;\n if (hasError || isStopped) {\n return EMPTY_SUBSCRIPTION;\n }\n this.currentObservers = null;\n observers.push(subscriber);\n return new Subscription(() => {\n this.currentObservers = null;\n arrRemove(observers, subscriber);\n });\n }\n\n /** @internal */\n protected _checkFinalizedStatuses(subscriber: Subscriber) {\n const { hasError, thrownError, isStopped } = this;\n if (hasError) {\n subscriber.error(thrownError);\n } else if (isStopped) {\n subscriber.complete();\n }\n }\n\n /**\n * Creates a new Observable with this Subject as the source. You can do this\n * to create custom Observer-side logic of the Subject and conceal it from\n * code that uses the Observable.\n * @return {Observable} Observable that the Subject casts to\n */\n asObservable(): Observable {\n const observable: any = new Observable();\n observable.source = this;\n return observable;\n }\n}\n\n/**\n * @class AnonymousSubject\n */\nexport class AnonymousSubject extends Subject {\n constructor(\n /** @deprecated Internal implementation detail, do not use directly. Will be made internal in v8. */\n public destination?: Observer,\n source?: Observable\n ) {\n super();\n this.source = source;\n }\n\n next(value: T) {\n this.destination?.next?.(value);\n }\n\n error(err: any) {\n this.destination?.error?.(err);\n }\n\n complete() {\n this.destination?.complete?.();\n }\n\n /** @internal */\n protected _subscribe(subscriber: Subscriber): Subscription {\n return this.source?.subscribe(subscriber) ?? EMPTY_SUBSCRIPTION;\n }\n}\n", "import { TimestampProvider } from '../types';\n\ninterface DateTimestampProvider extends TimestampProvider {\n delegate: TimestampProvider | undefined;\n}\n\nexport const dateTimestampProvider: DateTimestampProvider = {\n now() {\n // Use the variable rather than `this` so that the function can be called\n // without being bound to the provider.\n return (dateTimestampProvider.delegate || Date).now();\n },\n delegate: undefined,\n};\n", "import { Subject } from './Subject';\nimport { TimestampProvider } from './types';\nimport { Subscriber } from './Subscriber';\nimport { Subscription } from './Subscription';\nimport { dateTimestampProvider } from './scheduler/dateTimestampProvider';\n\n/**\n * A variant of {@link Subject} that \"replays\" old values to new subscribers by emitting them when they first subscribe.\n *\n * `ReplaySubject` has an internal buffer that will store a specified number of values that it has observed. Like `Subject`,\n * `ReplaySubject` \"observes\" values by having them passed to its `next` method. When it observes a value, it will store that\n * value for a time determined by the configuration of the `ReplaySubject`, as passed to its constructor.\n *\n * When a new subscriber subscribes to the `ReplaySubject` instance, it will synchronously emit all values in its buffer in\n * a First-In-First-Out (FIFO) manner. The `ReplaySubject` will also complete, if it has observed completion; and it will\n * error if it has observed an error.\n *\n * There are two main configuration items to be concerned with:\n *\n * 1. `bufferSize` - This will determine how many items are stored in the buffer, defaults to infinite.\n * 2. `windowTime` - The amount of time to hold a value in the buffer before removing it from the buffer.\n *\n * Both configurations may exist simultaneously. So if you would like to buffer a maximum of 3 values, as long as the values\n * are less than 2 seconds old, you could do so with a `new ReplaySubject(3, 2000)`.\n *\n * ### Differences with BehaviorSubject\n *\n * `BehaviorSubject` is similar to `new ReplaySubject(1)`, with a couple of exceptions:\n *\n * 1. `BehaviorSubject` comes \"primed\" with a single value upon construction.\n * 2. `ReplaySubject` will replay values, even after observing an error, where `BehaviorSubject` will not.\n *\n * @see {@link Subject}\n * @see {@link BehaviorSubject}\n * @see {@link shareReplay}\n */\nexport class ReplaySubject extends Subject {\n private _buffer: (T | number)[] = [];\n private _infiniteTimeWindow = true;\n\n /**\n * @param bufferSize The size of the buffer to replay on subscription\n * @param windowTime The amount of time the buffered items will stay buffered\n * @param timestampProvider An object with a `now()` method that provides the current timestamp. This is used to\n * calculate the amount of time something has been buffered.\n */\n constructor(\n private _bufferSize = Infinity,\n private _windowTime = Infinity,\n private _timestampProvider: TimestampProvider = dateTimestampProvider\n ) {\n super();\n this._infiniteTimeWindow = _windowTime === Infinity;\n this._bufferSize = Math.max(1, _bufferSize);\n this._windowTime = Math.max(1, _windowTime);\n }\n\n next(value: T): void {\n const { isStopped, _buffer, _infiniteTimeWindow, _timestampProvider, _windowTime } = this;\n if (!isStopped) {\n _buffer.push(value);\n !_infiniteTimeWindow && _buffer.push(_timestampProvider.now() + _windowTime);\n }\n this._trimBuffer();\n super.next(value);\n }\n\n /** @internal */\n protected _subscribe(subscriber: Subscriber): Subscription {\n this._throwIfClosed();\n this._trimBuffer();\n\n const subscription = this._innerSubscribe(subscriber);\n\n const { _infiniteTimeWindow, _buffer } = this;\n // We use a copy here, so reentrant code does not mutate our array while we're\n // emitting it to a new subscriber.\n const copy = _buffer.slice();\n for (let i = 0; i < copy.length && !subscriber.closed; i += _infiniteTimeWindow ? 1 : 2) {\n subscriber.next(copy[i] as T);\n }\n\n this._checkFinalizedStatuses(subscriber);\n\n return subscription;\n }\n\n private _trimBuffer() {\n const { _bufferSize, _timestampProvider, _buffer, _infiniteTimeWindow } = this;\n // If we don't have an infinite buffer size, and we're over the length,\n // use splice to truncate the old buffer values off. Note that we have to\n // double the size for instances where we're not using an infinite time window\n // because we're storing the values and the timestamps in the same array.\n const adjustedBufferSize = (_infiniteTimeWindow ? 1 : 2) * _bufferSize;\n _bufferSize < Infinity && adjustedBufferSize < _buffer.length && _buffer.splice(0, _buffer.length - adjustedBufferSize);\n\n // Now, if we're not in an infinite time window, remove all values where the time is\n // older than what is allowed.\n if (!_infiniteTimeWindow) {\n const now = _timestampProvider.now();\n let last = 0;\n // Search the array for the first timestamp that isn't expired and\n // truncate the buffer up to that point.\n for (let i = 1; i < _buffer.length && (_buffer[i] as number) <= now; i += 2) {\n last = i;\n }\n last && _buffer.splice(0, last + 1);\n }\n }\n}\n", "import { Scheduler } from '../Scheduler';\nimport { Subscription } from '../Subscription';\nimport { SchedulerAction } from '../types';\n\n/**\n * A unit of work to be executed in a `scheduler`. An action is typically\n * created from within a {@link SchedulerLike} and an RxJS user does not need to concern\n * themselves about creating and manipulating an Action.\n *\n * ```ts\n * class Action extends Subscription {\n * new (scheduler: Scheduler, work: (state?: T) => void);\n * schedule(state?: T, delay: number = 0): Subscription;\n * }\n * ```\n *\n * @class Action\n */\nexport class Action extends Subscription {\n constructor(scheduler: Scheduler, work: (this: SchedulerAction, state?: T) => void) {\n super();\n }\n /**\n * Schedules this action on its parent {@link SchedulerLike} for execution. May be passed\n * some context object, `state`. May happen at some point in the future,\n * according to the `delay` parameter, if specified.\n * @param {T} [state] Some contextual data that the `work` function uses when\n * called by the Scheduler.\n * @param {number} [delay] Time to wait before executing the work, where the\n * time unit is implicit and defined by the Scheduler.\n * @return {void}\n */\n public schedule(state?: T, delay: number = 0): Subscription {\n return this;\n }\n}\n", "import type { TimerHandle } from './timerHandle';\ntype SetIntervalFunction = (handler: () => void, timeout?: number, ...args: any[]) => TimerHandle;\ntype ClearIntervalFunction = (handle: TimerHandle) => void;\n\ninterface IntervalProvider {\n setInterval: SetIntervalFunction;\n clearInterval: ClearIntervalFunction;\n delegate:\n | {\n setInterval: SetIntervalFunction;\n clearInterval: ClearIntervalFunction;\n }\n | undefined;\n}\n\nexport const intervalProvider: IntervalProvider = {\n // When accessing the delegate, use the variable rather than `this` so that\n // the functions can be called without being bound to the provider.\n setInterval(handler: () => void, timeout?: number, ...args) {\n const { delegate } = intervalProvider;\n if (delegate?.setInterval) {\n return delegate.setInterval(handler, timeout, ...args);\n }\n return setInterval(handler, timeout, ...args);\n },\n clearInterval(handle) {\n const { delegate } = intervalProvider;\n return (delegate?.clearInterval || clearInterval)(handle as any);\n },\n delegate: undefined,\n};\n", "import { Action } from './Action';\nimport { SchedulerAction } from '../types';\nimport { Subscription } from '../Subscription';\nimport { AsyncScheduler } from './AsyncScheduler';\nimport { intervalProvider } from './intervalProvider';\nimport { arrRemove } from '../util/arrRemove';\nimport { TimerHandle } from './timerHandle';\n\nexport class AsyncAction extends Action {\n public id: TimerHandle | undefined;\n public state?: T;\n // @ts-ignore: Property has no initializer and is not definitely assigned\n public delay: number;\n protected pending: boolean = false;\n\n constructor(protected scheduler: AsyncScheduler, protected work: (this: SchedulerAction, state?: T) => void) {\n super(scheduler, work);\n }\n\n public schedule(state?: T, delay: number = 0): Subscription {\n if (this.closed) {\n return this;\n }\n\n // Always replace the current state with the new state.\n this.state = state;\n\n const id = this.id;\n const scheduler = this.scheduler;\n\n //\n // Important implementation note:\n //\n // Actions only execute once by default, unless rescheduled from within the\n // scheduled callback. This allows us to implement single and repeat\n // actions via the same code path, without adding API surface area, as well\n // as mimic traditional recursion but across asynchronous boundaries.\n //\n // However, JS runtimes and timers distinguish between intervals achieved by\n // serial `setTimeout` calls vs. a single `setInterval` call. An interval of\n // serial `setTimeout` calls can be individually delayed, which delays\n // scheduling the next `setTimeout`, and so on. `setInterval` attempts to\n // guarantee the interval callback will be invoked more precisely to the\n // interval period, regardless of load.\n //\n // Therefore, we use `setInterval` to schedule single and repeat actions.\n // If the action reschedules itself with the same delay, the interval is not\n // canceled. If the action doesn't reschedule, or reschedules with a\n // different delay, the interval will be canceled after scheduled callback\n // execution.\n //\n if (id != null) {\n this.id = this.recycleAsyncId(scheduler, id, delay);\n }\n\n // Set the pending flag indicating that this action has been scheduled, or\n // has recursively rescheduled itself.\n this.pending = true;\n\n this.delay = delay;\n // If this action has already an async Id, don't request a new one.\n this.id = this.id ?? this.requestAsyncId(scheduler, this.id, delay);\n\n return this;\n }\n\n protected requestAsyncId(scheduler: AsyncScheduler, _id?: TimerHandle, delay: number = 0): TimerHandle {\n return intervalProvider.setInterval(scheduler.flush.bind(scheduler, this), delay);\n }\n\n protected recycleAsyncId(_scheduler: AsyncScheduler, id?: TimerHandle, delay: number | null = 0): TimerHandle | undefined {\n // If this action is rescheduled with the same delay time, don't clear the interval id.\n if (delay != null && this.delay === delay && this.pending === false) {\n return id;\n }\n // Otherwise, if the action's delay time is different from the current delay,\n // or the action has been rescheduled before it's executed, clear the interval id\n if (id != null) {\n intervalProvider.clearInterval(id);\n }\n\n return undefined;\n }\n\n /**\n * Immediately executes this action and the `work` it contains.\n * @return {any}\n */\n public execute(state: T, delay: number): any {\n if (this.closed) {\n return new Error('executing a cancelled action');\n }\n\n this.pending = false;\n const error = this._execute(state, delay);\n if (error) {\n return error;\n } else if (this.pending === false && this.id != null) {\n // Dequeue if the action didn't reschedule itself. Don't call\n // unsubscribe(), because the action could reschedule later.\n // For example:\n // ```\n // scheduler.schedule(function doWork(counter) {\n // /* ... I'm a busy worker bee ... */\n // var originalAction = this;\n // /* wait 100ms before rescheduling the action */\n // setTimeout(function () {\n // originalAction.schedule(counter + 1);\n // }, 100);\n // }, 1000);\n // ```\n this.id = this.recycleAsyncId(this.scheduler, this.id, null);\n }\n }\n\n protected _execute(state: T, _delay: number): any {\n let errored: boolean = false;\n let errorValue: any;\n try {\n this.work(state);\n } catch (e) {\n errored = true;\n // HACK: Since code elsewhere is relying on the \"truthiness\" of the\n // return here, we can't have it return \"\" or 0 or false.\n // TODO: Clean this up when we refactor schedulers mid-version-8 or so.\n errorValue = e ? e : new Error('Scheduled action threw falsy error');\n }\n if (errored) {\n this.unsubscribe();\n return errorValue;\n }\n }\n\n unsubscribe() {\n if (!this.closed) {\n const { id, scheduler } = this;\n const { actions } = scheduler;\n\n this.work = this.state = this.scheduler = null!;\n this.pending = false;\n\n arrRemove(actions, this);\n if (id != null) {\n this.id = this.recycleAsyncId(scheduler, id, null);\n }\n\n this.delay = null!;\n super.unsubscribe();\n }\n }\n}\n", "import { Action } from './scheduler/Action';\nimport { Subscription } from './Subscription';\nimport { SchedulerLike, SchedulerAction } from './types';\nimport { dateTimestampProvider } from './scheduler/dateTimestampProvider';\n\n/**\n * An execution context and a data structure to order tasks and schedule their\n * execution. Provides a notion of (potentially virtual) time, through the\n * `now()` getter method.\n *\n * Each unit of work in a Scheduler is called an `Action`.\n *\n * ```ts\n * class Scheduler {\n * now(): number;\n * schedule(work, delay?, state?): Subscription;\n * }\n * ```\n *\n * @class Scheduler\n * @deprecated Scheduler is an internal implementation detail of RxJS, and\n * should not be used directly. Rather, create your own class and implement\n * {@link SchedulerLike}. Will be made internal in v8.\n */\nexport class Scheduler implements SchedulerLike {\n public static now: () => number = dateTimestampProvider.now;\n\n constructor(private schedulerActionCtor: typeof Action, now: () => number = Scheduler.now) {\n this.now = now;\n }\n\n /**\n * A getter method that returns a number representing the current time\n * (at the time this function was called) according to the scheduler's own\n * internal clock.\n * @return {number} A number that represents the current time. May or may not\n * have a relation to wall-clock time. May or may not refer to a time unit\n * (e.g. milliseconds).\n */\n public now: () => number;\n\n /**\n * Schedules a function, `work`, for execution. May happen at some point in\n * the future, according to the `delay` parameter, if specified. May be passed\n * some context object, `state`, which will be passed to the `work` function.\n *\n * The given arguments will be processed an stored as an Action object in a\n * queue of actions.\n *\n * @param {function(state: ?T): ?Subscription} work A function representing a\n * task, or some unit of work to be executed by the Scheduler.\n * @param {number} [delay] Time to wait before executing the work, where the\n * time unit is implicit and defined by the Scheduler itself.\n * @param {T} [state] Some contextual data that the `work` function uses when\n * called by the Scheduler.\n * @return {Subscription} A subscription in order to be able to unsubscribe\n * the scheduled work.\n */\n public schedule(work: (this: SchedulerAction, state?: T) => void, delay: number = 0, state?: T): Subscription {\n return new this.schedulerActionCtor(this, work).schedule(state, delay);\n }\n}\n", "import { Scheduler } from '../Scheduler';\nimport { Action } from './Action';\nimport { AsyncAction } from './AsyncAction';\nimport { TimerHandle } from './timerHandle';\n\nexport class AsyncScheduler extends Scheduler {\n public actions: Array> = [];\n /**\n * A flag to indicate whether the Scheduler is currently executing a batch of\n * queued actions.\n * @type {boolean}\n * @internal\n */\n public _active: boolean = false;\n /**\n * An internal ID used to track the latest asynchronous task such as those\n * coming from `setTimeout`, `setInterval`, `requestAnimationFrame`, and\n * others.\n * @type {any}\n * @internal\n */\n public _scheduled: TimerHandle | undefined;\n\n constructor(SchedulerAction: typeof Action, now: () => number = Scheduler.now) {\n super(SchedulerAction, now);\n }\n\n public flush(action: AsyncAction): void {\n const { actions } = this;\n\n if (this._active) {\n actions.push(action);\n return;\n }\n\n let error: any;\n this._active = true;\n\n do {\n if ((error = action.execute(action.state, action.delay))) {\n break;\n }\n } while ((action = actions.shift()!)); // exhaust the scheduler queue\n\n this._active = false;\n\n if (error) {\n while ((action = actions.shift()!)) {\n action.unsubscribe();\n }\n throw error;\n }\n }\n}\n", "import { AsyncAction } from './AsyncAction';\nimport { AsyncScheduler } from './AsyncScheduler';\n\n/**\n *\n * Async Scheduler\n *\n * Schedule task as if you used setTimeout(task, duration)\n *\n * `async` scheduler schedules tasks asynchronously, by putting them on the JavaScript\n * event loop queue. It is best used to delay tasks in time or to schedule tasks repeating\n * in intervals.\n *\n * If you just want to \"defer\" task, that is to perform it right after currently\n * executing synchronous code ends (commonly achieved by `setTimeout(deferredTask, 0)`),\n * better choice will be the {@link asapScheduler} scheduler.\n *\n * ## Examples\n * Use async scheduler to delay task\n * ```ts\n * import { asyncScheduler } from 'rxjs';\n *\n * const task = () => console.log('it works!');\n *\n * asyncScheduler.schedule(task, 2000);\n *\n * // After 2 seconds logs:\n * // \"it works!\"\n * ```\n *\n * Use async scheduler to repeat task in intervals\n * ```ts\n * import { asyncScheduler } from 'rxjs';\n *\n * function task(state) {\n * console.log(state);\n * this.schedule(state + 1, 1000); // `this` references currently executing Action,\n * // which we reschedule with new state and delay\n * }\n *\n * asyncScheduler.schedule(task, 3000, 0);\n *\n * // Logs:\n * // 0 after 3s\n * // 1 after 4s\n * // 2 after 5s\n * // 3 after 6s\n * ```\n */\n\nexport const asyncScheduler = new AsyncScheduler(AsyncAction);\n\n/**\n * @deprecated Renamed to {@link asyncScheduler}. Will be removed in v8.\n */\nexport const async = asyncScheduler;\n", "import { AsyncAction } from './AsyncAction';\nimport { AnimationFrameScheduler } from './AnimationFrameScheduler';\nimport { SchedulerAction } from '../types';\nimport { animationFrameProvider } from './animationFrameProvider';\nimport { TimerHandle } from './timerHandle';\n\nexport class AnimationFrameAction extends AsyncAction {\n constructor(protected scheduler: AnimationFrameScheduler, protected work: (this: SchedulerAction, state?: T) => void) {\n super(scheduler, work);\n }\n\n protected requestAsyncId(scheduler: AnimationFrameScheduler, id?: TimerHandle, delay: number = 0): TimerHandle {\n // If delay is greater than 0, request as an async action.\n if (delay !== null && delay > 0) {\n return super.requestAsyncId(scheduler, id, delay);\n }\n // Push the action to the end of the scheduler queue.\n scheduler.actions.push(this);\n // If an animation frame has already been requested, don't request another\n // one. If an animation frame hasn't been requested yet, request one. Return\n // the current animation frame request id.\n return scheduler._scheduled || (scheduler._scheduled = animationFrameProvider.requestAnimationFrame(() => scheduler.flush(undefined)));\n }\n\n protected recycleAsyncId(scheduler: AnimationFrameScheduler, id?: TimerHandle, delay: number = 0): TimerHandle | undefined {\n // If delay exists and is greater than 0, or if the delay is null (the\n // action wasn't rescheduled) but was originally scheduled as an async\n // action, then recycle as an async action.\n if (delay != null ? delay > 0 : this.delay > 0) {\n return super.recycleAsyncId(scheduler, id, delay);\n }\n // If the scheduler queue has no remaining actions with the same async id,\n // cancel the requested animation frame and set the scheduled flag to\n // undefined so the next AnimationFrameAction will request its own.\n const { actions } = scheduler;\n if (id != null && actions[actions.length - 1]?.id !== id) {\n animationFrameProvider.cancelAnimationFrame(id as number);\n scheduler._scheduled = undefined;\n }\n // Return undefined so the action knows to request a new async id if it's rescheduled.\n return undefined;\n }\n}\n", "import { AsyncAction } from './AsyncAction';\nimport { AsyncScheduler } from './AsyncScheduler';\n\nexport class AnimationFrameScheduler extends AsyncScheduler {\n public flush(action?: AsyncAction): void {\n this._active = true;\n // The async id that effects a call to flush is stored in _scheduled.\n // Before executing an action, it's necessary to check the action's async\n // id to determine whether it's supposed to be executed in the current\n // flush.\n // Previous implementations of this method used a count to determine this,\n // but that was unsound, as actions that are unsubscribed - i.e. cancelled -\n // are removed from the actions array and that can shift actions that are\n // scheduled to be executed in a subsequent flush into positions at which\n // they are executed within the current flush.\n const flushId = this._scheduled;\n this._scheduled = undefined;\n\n const { actions } = this;\n let error: any;\n action = action || actions.shift()!;\n\n do {\n if ((error = action.execute(action.state, action.delay))) {\n break;\n }\n } while ((action = actions[0]) && action.id === flushId && actions.shift());\n\n this._active = false;\n\n if (error) {\n while ((action = actions[0]) && action.id === flushId && actions.shift()) {\n action.unsubscribe();\n }\n throw error;\n }\n }\n}\n", "import { AnimationFrameAction } from './AnimationFrameAction';\nimport { AnimationFrameScheduler } from './AnimationFrameScheduler';\n\n/**\n *\n * Animation Frame Scheduler\n *\n * Perform task when `window.requestAnimationFrame` would fire\n *\n * When `animationFrame` scheduler is used with delay, it will fall back to {@link asyncScheduler} scheduler\n * behaviour.\n *\n * Without delay, `animationFrame` scheduler can be used to create smooth browser animations.\n * It makes sure scheduled task will happen just before next browser content repaint,\n * thus performing animations as efficiently as possible.\n *\n * ## Example\n * Schedule div height animation\n * ```ts\n * // html:
\n * import { animationFrameScheduler } from 'rxjs';\n *\n * const div = document.querySelector('div');\n *\n * animationFrameScheduler.schedule(function(height) {\n * div.style.height = height + \"px\";\n *\n * this.schedule(height + 1); // `this` references currently executing Action,\n * // which we reschedule with new state\n * }, 0, 0);\n *\n * // You will see a div element growing in height\n * ```\n */\n\nexport const animationFrameScheduler = new AnimationFrameScheduler(AnimationFrameAction);\n\n/**\n * @deprecated Renamed to {@link animationFrameScheduler}. Will be removed in v8.\n */\nexport const animationFrame = animationFrameScheduler;\n", "import { Observable } from '../Observable';\nimport { SchedulerLike } from '../types';\n\n/**\n * A simple Observable that emits no items to the Observer and immediately\n * emits a complete notification.\n *\n * Just emits 'complete', and nothing else.\n *\n * ![](empty.png)\n *\n * A simple Observable that only emits the complete notification. It can be used\n * for composing with other Observables, such as in a {@link mergeMap}.\n *\n * ## Examples\n *\n * Log complete notification\n *\n * ```ts\n * import { EMPTY } from 'rxjs';\n *\n * EMPTY.subscribe({\n * next: () => console.log('Next'),\n * complete: () => console.log('Complete!')\n * });\n *\n * // Outputs\n * // Complete!\n * ```\n *\n * Emit the number 7, then complete\n *\n * ```ts\n * import { EMPTY, startWith } from 'rxjs';\n *\n * const result = EMPTY.pipe(startWith(7));\n * result.subscribe(x => console.log(x));\n *\n * // Outputs\n * // 7\n * ```\n *\n * Map and flatten only odd numbers to the sequence `'a'`, `'b'`, `'c'`\n *\n * ```ts\n * import { interval, mergeMap, of, EMPTY } from 'rxjs';\n *\n * const interval$ = interval(1000);\n * const result = interval$.pipe(\n * mergeMap(x => x % 2 === 1 ? of('a', 'b', 'c') : EMPTY),\n * );\n * result.subscribe(x => console.log(x));\n *\n * // Results in the following to the console:\n * // x is equal to the count on the interval, e.g. (0, 1, 2, 3, ...)\n * // x will occur every 1000ms\n * // if x % 2 is equal to 1, print a, b, c (each on its own)\n * // if x % 2 is not equal to 1, nothing will be output\n * ```\n *\n * @see {@link Observable}\n * @see {@link NEVER}\n * @see {@link of}\n * @see {@link throwError}\n */\nexport const EMPTY = new Observable((subscriber) => subscriber.complete());\n\n/**\n * @param scheduler A {@link SchedulerLike} to use for scheduling\n * the emission of the complete notification.\n * @deprecated Replaced with the {@link EMPTY} constant or {@link scheduled} (e.g. `scheduled([], scheduler)`). Will be removed in v8.\n */\nexport function empty(scheduler?: SchedulerLike) {\n return scheduler ? emptyScheduled(scheduler) : EMPTY;\n}\n\nfunction emptyScheduled(scheduler: SchedulerLike) {\n return new Observable((subscriber) => scheduler.schedule(() => subscriber.complete()));\n}\n", "import { SchedulerLike } from '../types';\nimport { isFunction } from './isFunction';\n\nexport function isScheduler(value: any): value is SchedulerLike {\n return value && isFunction(value.schedule);\n}\n", "import { SchedulerLike } from '../types';\nimport { isFunction } from './isFunction';\nimport { isScheduler } from './isScheduler';\n\nfunction last(arr: T[]): T | undefined {\n return arr[arr.length - 1];\n}\n\nexport function popResultSelector(args: any[]): ((...args: unknown[]) => unknown) | undefined {\n return isFunction(last(args)) ? args.pop() : undefined;\n}\n\nexport function popScheduler(args: any[]): SchedulerLike | undefined {\n return isScheduler(last(args)) ? args.pop() : undefined;\n}\n\nexport function popNumber(args: any[], defaultValue: number): number {\n return typeof last(args) === 'number' ? args.pop()! : defaultValue;\n}\n", "export const isArrayLike = ((x: any): x is ArrayLike => x && typeof x.length === 'number' && typeof x !== 'function');", "import { isFunction } from \"./isFunction\";\n\n/**\n * Tests to see if the object is \"thennable\".\n * @param value the object to test\n */\nexport function isPromise(value: any): value is PromiseLike {\n return isFunction(value?.then);\n}\n", "import { InteropObservable } from '../types';\nimport { observable as Symbol_observable } from '../symbol/observable';\nimport { isFunction } from './isFunction';\n\n/** Identifies an input as being Observable (but not necessary an Rx Observable) */\nexport function isInteropObservable(input: any): input is InteropObservable {\n return isFunction(input[Symbol_observable]);\n}\n", "import { isFunction } from './isFunction';\n\nexport function isAsyncIterable(obj: any): obj is AsyncIterable {\n return Symbol.asyncIterator && isFunction(obj?.[Symbol.asyncIterator]);\n}\n", "/**\n * Creates the TypeError to throw if an invalid object is passed to `from` or `scheduled`.\n * @param input The object that was passed.\n */\nexport function createInvalidObservableTypeError(input: any) {\n // TODO: We should create error codes that can be looked up, so this can be less verbose.\n return new TypeError(\n `You provided ${\n input !== null && typeof input === 'object' ? 'an invalid object' : `'${input}'`\n } where a stream was expected. You can provide an Observable, Promise, ReadableStream, Array, AsyncIterable, or Iterable.`\n );\n}\n", "export function getSymbolIterator(): symbol {\n if (typeof Symbol !== 'function' || !Symbol.iterator) {\n return '@@iterator' as any;\n }\n\n return Symbol.iterator;\n}\n\nexport const iterator = getSymbolIterator();\n", "import { iterator as Symbol_iterator } from '../symbol/iterator';\nimport { isFunction } from './isFunction';\n\n/** Identifies an input as being an Iterable */\nexport function isIterable(input: any): input is Iterable {\n return isFunction(input?.[Symbol_iterator]);\n}\n", "import { ReadableStreamLike } from '../types';\nimport { isFunction } from './isFunction';\n\nexport async function* readableStreamLikeToAsyncGenerator(readableStream: ReadableStreamLike): AsyncGenerator {\n const reader = readableStream.getReader();\n try {\n while (true) {\n const { value, done } = await reader.read();\n if (done) {\n return;\n }\n yield value!;\n }\n } finally {\n reader.releaseLock();\n }\n}\n\nexport function isReadableStreamLike(obj: any): obj is ReadableStreamLike {\n // We don't want to use instanceof checks because they would return\n // false for instances from another Realm, like an