Sorry, but the page you were trying to view does not exist.
+
+
+
+
diff --git a/demo/src/static/LICENSE.txt b/demo/src/static/LICENSE.txt
new file mode 100644
index 0000000..294e91d
--- /dev/null
+++ b/demo/src/static/LICENSE.txt
@@ -0,0 +1,19 @@
+Copyright (c) HTML5 Boilerplate
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/demo/src/static/css/main.css b/demo/src/static/css/main.css
new file mode 100644
index 0000000..043f520
--- /dev/null
+++ b/demo/src/static/css/main.css
@@ -0,0 +1,656 @@
+/*! HTML5 Boilerplate v8.0.0 | MIT License | https://html5boilerplate.com/ */
+
+/* main.css 2.1.0 | MIT License | https://github.com/h5bp/main.css#readme */
+/*
+ * What follows is the result of much research on cross-browser styling.
+ * Credit left inline and big thanks to Nicolas Gallagher, Jonathan Neal,
+ * Kroc Camen, and the H5BP dev community and team.
+ */
+
+/* ==========================================================================
+ Base styles: opinionated defaults
+ ========================================================================== */
+
+:root {
+ --w-standard: 80rem;
+ --w-example-wrapped: 600px;
+
+ --block-margin-vertical: 3.75rem;
+ --block-padding-vertical: 1.875rem;
+
+ --c-aero-blue: #abffd9;
+ --c-alto: #dfdfdf;
+ --c-athens-gray: #f8f8f9;
+ --c-black: #000;
+ --c-black-o2: rgba(0, 0, 0, 0.2);
+ --c-black-o4: rgba(0, 0, 0, 0.4);
+ --c-black-o8: rgba(0, 0, 0, 0.8);
+ --c-deep-cove: #061a40;
+ --c-deep-cove-o2: rgba(6, 26, 64, 0.2);
+ --c-deep-cove-o3: rgba(6, 26, 64, 0.3);
+ --c-deep-cove-o6: rgba(6, 26, 64, 0.6);
+ --c-deep-cove-o8: rgba(6, 26, 64, 0.8);
+ --c-dove-gray: #636363;
+ --c-egg-sour: #fff3dd;
+ --c-gallery: #eeeeee;
+ --c-jacarta: #2f285b;
+ --c-matisse: #1c5298;
+ --c-matisse-darker: #03397f;
+ --c-matisse-o1: rgba(28, 82, 152, 0.1);
+ --c-matisse-o2: rgba(28, 82, 152, 0.2);
+ --c-mercury: #e9e9e9;
+ --c-mine-shaft: #272727;
+ --c-ocean-green: #46bc86;
+ --c-picton-blue: #1fc8e7;
+ --c-seashell: #f1f1f1;
+ --c-silver: #c4c4c4;
+ --c-silver-chalice: #a5a5a5;
+ --c-slate-gray: #6b788e;
+ --c-stratos: #00133e;
+ --c-texas-rose: #fdbd50;
+ --c-texas-rose-darker: #e4a437;
+ --c-torch-red: #ff0033;
+ --c-white: #fff;
+ --c-white-darker: #e6e6e6;
+ --c-white-o3: rgba(255, 255, 255, 0.3);
+ --c-white-o6: rgba(255, 255, 255, 0.6);
+
+ --f-default-size: 1rem;
+ --f-regular: "Inter", sans-serif;
+}
+
+html {
+ font-family: var(--f-regular);
+ color: var(--c-mine-shaft);
+ font-size: 1em;
+ line-height: 1.4;
+}
+
+/*
+ * Remove text-shadow in selection highlight:
+ * https://twitter.com/miketaylr/status/12228805301
+ *
+ * Vendor-prefixed and regular ::selection selectors cannot be combined:
+ * https://stackoverflow.com/a/16982510/7133471
+ *
+ * Customize the background color to match your design.
+ */
+
+::-moz-selection {
+ background: #b3d4fc;
+ text-shadow: none;
+}
+
+::selection {
+ background: var(--c-picton-blue);
+ text-shadow: none;
+}
+
+/*
+ * A better looking default horizontal rule
+ */
+
+hr {
+ display: block;
+ height: 1px;
+ border: 0;
+ border-top: 1px solid #ccc;
+ margin: 1em 0;
+ padding: 0;
+}
+
+/*
+ * Remove the gap between audio, canvas, iframes,
+ * images, videos and the bottom of their containers:
+ * https://github.com/h5bp/html5-boilerplate/issues/440
+ */
+
+audio,
+canvas,
+iframe,
+img,
+svg,
+video {
+ vertical-align: middle;
+}
+
+/*
+ * Remove default fieldset styles.
+ */
+
+fieldset {
+ border: 0;
+ margin: 0;
+ padding: 0;
+}
+
+/*
+ * Allow only vertical resizing of textareas.
+ */
+
+textarea {
+ resize: vertical;
+}
+
+/* ==========================================================================
+ Author's custom styles
+ ========================================================================== */
+
+.wrapper {
+ margin: 0 auto;
+ max-width: var(--w-example-wrapped);
+ padding: 1rem;
+}
+
+.card {
+ border: 1px solid var(--c-mercury);
+ padding: 1rem;
+ margin-bottom: 1rem;
+ transition: filter, opacity linear .5s;
+}
+
+.card.collapsed {
+ opacity: .25;
+ filter: grayscale(50%);
+ pointer-events: none;
+}
+
+.card :first-of-type {
+ margin-top: 0;
+}
+
+form {
+ max-width: 100%;
+}
+
+.form__field {
+ padding: 1rem 0;
+}
+
+h1 {
+ color: var(--c-matisse);
+ font-family: var(--f-regular);
+ font-size: 3.125rem;
+ font-weight: bold;
+ letter-spacing: -0.02em;
+ line-height: 1em;
+}
+
+header h1 {
+ margin-top: 1rem;
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ grid-template-columns: 50% 50%;
+}
+
+header span {
+ font-size: 1.95rem;
+ line-height: 1;
+}
+
+@media screen and (min-width: 1024px) {
+ header span {
+ font-size: 2.6rem;
+ }
+}
+
+
+
+header .logo {
+ margin-right: 1rem;
+}
+
+h3 {
+ color: var(--c-deep-cove);
+ letter-spacing: -0.02em;
+ font-family: var(--f-regular);
+ margin-bottom: 0;
+ font-size: 1.875rem;
+ font-weight: 600;
+ line-height: 1.3em;
+}
+
+h4 {
+ color: var(--c-deep-cove);
+ font-size: 1.2em;
+ letter-spacing: -0.04em;
+ margin-bottom: 0;
+}
+
+header + p {
+ font-size: .9rem;
+}
+
+a {
+ color: var(--c-matisse);
+ text-decoration: none;
+ transition: color 0.3s ease-in-out;
+}
+
+a:focus, a:hover {
+ color: var(--c-deep-cove);
+}
+
+legend {
+ font-family: var(--f-regular);
+ font-size: 1.25rem;
+ font-weight: bold;
+ letter-spacing: -0.01em;
+ line-height: 1.3em;
+}
+
+label,
+legend {
+ display: block;
+ color: var(--c-matisse);
+ font-family: var(--f-regular);
+ font-size: 0.625rem;
+ font-style: normal;
+ font-weight: 600;
+ letter-spacing: 0.05em;
+ line-height: 1.5em;
+ margin: 0;
+ text-transform: uppercase;
+ width: 100%;
+}
+
+fieldset label {
+ font-size: 1rem;
+ text-transform: none;
+ letter-spacing: normal;
+}
+
+input[type="text"],
+input[type="email"] {
+ border-color: var(--c-black-o4);
+ border-style: solid;
+ border-width: 0 0 1px;
+ padding-left: 0;
+ padding-right: 0;
+ background-color: var(--c-white);
+ border-radius: 4px;
+ color: var(--c-black);
+ font-family: var(--f-regular);
+ font-size: 1rem;
+ font-style: normal;
+ font-weight: normal;
+ line-height: 1.5em;
+ outline: 0;
+ display: block;
+ max-width: 100%;
+ width: 100%;
+}
+
+.assurance,
+.mode {
+ padding-left: 50px;
+ min-height: 50px;
+ line-height: 50px;
+ background-size: 44px;
+ background-repeat: no-repeat;
+ background-color: transparent;
+ background-position: 0 50%;
+}
+
+.mode--enrol {
+ background-image: url(../img/onboarding-woman-yellow.png);
+}
+
+.mode--verify {
+ background-image: url(../img/gpa-authenticated-woman-blue.png);
+}
+
+.assurance--genuine_presence {
+ background-image: url(../img/gpa-side-woman.png);
+}
+
+.assurance--liveness {
+ background-image: url(../img/liveness-side--woman.png);
+}
+
+.ipbutton,
+button {
+ background-color: var(--c-matisse);
+ color: var(--c-white);
+ border-radius: 4px;
+ font-size: 0.75rem;
+ font-weight: 700;
+ line-height: 1.25em;
+ padding: 1rem 1.3rem;
+ text-transform: uppercase;
+ align-items: center;
+ border-style: solid;
+ border-color: var(--c-matisse);
+ border-width: 2px;
+ cursor: pointer;
+ display: inline-flex;
+ font-family: var(--f-regular);
+ font-style: normal;
+ justify-content: center;
+ outline: 0;
+ text-align: center;
+ text-decoration: none;
+ transition: background-color 0.3s ease-in-out, border-color 0.3s ease-in-out, color 0.3s ease-in-out,
+ opacity 0.3s ease-in-out;
+}
+
+.ipbutton--lozenge {
+ border-radius: 5rem;
+ font-size: 0.9375rem;
+ font-weight: 600;
+ letter-spacing: -0.02em;
+ line-height: 1.3em;
+ padding: 0.4rem 0.7rem;
+ text-transform: none;
+}
+
+.ipbutton--texas-rose {
+ background-color: var(--c-texas-rose);
+ border-color: var(--c-texas-rose);
+ color: var(--c-deep-cove);
+}
+
+.ipbutton--texas-rose:focus,
+.ipbutton--texas-rose:hover {
+ background-color: var(--c-texas-rose-darker);
+ border-color: var(--c-texas-rose-darker);
+}
+
+button.action-restart {
+ padding-right: 40px;
+ background-image: url(../img/arrow-right.svg);
+ background-repeat: no-repeat;
+ /* background-size: 40px; */
+ background-position: 90% 50%;
+}
+
+button.action-check-permission {
+ margin-left: 1em;
+}
+
+button:hover,
+button:focus {
+ background-color: var(--c-matisse-darker);
+ border-color: var(--c-matisse-darker);
+ color: var(--c-white);
+}
+
+pre {
+ background: var(--c-silver);
+ color: var(--c-mine-shaft);
+ font-size: 0.8em;
+ padding: 1rem;
+ border-radius: 4px;
+}
+
+footer {
+ color: var(--c-dove-gray);
+ font-size: 0.875rem;
+}
+
+footer a {
+ color: var(--c-dove-gray);
+ font-weight: 600;
+ text-decoration: none;
+}
+
+/* iProov Web SDK overrides */
+.progress {
+ margin: 2rem 0;
+ position: relative;
+ border-radius: 4px;
+ overflow: hidden;
+ max-width: 100%;
+ height: 3rem;
+ background: var(--c-slate-gray);
+}
+
+.progress__inner {
+ position: absolute;
+ transition: width cubic-bezier(0.75, 0.02, 1, 0.27) 0.3s;
+ left: 0;
+ top: 0;
+ bottom: 0;
+ background: var(--c-matisse);
+}
+
+.progress__text {
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ line-height: 3rem;
+ text-align: center;
+ color: white;
+ text-transform: uppercase;
+ font-weight: 600;
+}
+
+.state {
+ background-size: 80px;
+ background-repeat: no-repeat;
+ background-position: 100% 0;
+ margin-bottom: 1rem;
+ padding-right: calc(80px + 1rem);
+}
+
+
+.state--passed {
+ background-image: url(../img/gpa-tick.png);
+}
+
+.state--cancelled,
+.state--error,
+.state--failed {
+ background-image: url('../img/No-not-worked-woman-yellow.png');
+ padding-right: calc(1rem + 80px);
+}
+
+[slot=ready] h3 {
+ font-size: 1.5rem;
+}
+
+.error-container {
+ background-color: var(--c-egg-sour);
+ color: var(--c-torch-red);
+ border-radius: 4px;
+ border: 1px solid var(--c-torch-red);
+ padding: 1rem;
+ margin-top: 1rem;
+}
+
+.error-container h4, .error-container p {
+ color: inherit;
+ margin-bottom: 0;
+}
+
+.support-container {
+ margin: 1rem 0 0;
+ font-size: .8rem;
+ background-repeat: no-repeat;
+ padding-left: 2rem;
+ background-size: 1.5rem;
+ line-height: 1.5rem;
+}
+
+.support-container--ok {
+ background-image: url(../img/thumbs-up.png);
+ color: var(--c-ocean-green);
+}
+
+.support-container--error {
+ background-image: url(../img/thumbs-down.png);
+ color: var(--c-torch-red);
+}
+
+/* ==========================================================================
+ Helper classes
+ ========================================================================== */
+
+/*
+ * Hide visually and from screen readers
+ */
+
+.hidden,
+[hidden] {
+ display: none !important;
+}
+
+/*
+ * Hide only visually, but have it available for screen readers:
+ * https://snook.ca/archives/html_and_css/hiding-content-for-accessibility
+ *
+ * 1. For long content, line feeds are not interpreted as spaces and small width
+ * causes content to wrap 1 word per line:
+ * https://medium.com/@jessebeach/beware-smushed-off-screen-accessible-text-5952a4c2cbfe
+ */
+
+.sr-only {
+ border: 0;
+ clip: rect(0, 0, 0, 0);
+ height: 1px;
+ margin: -1px;
+ overflow: hidden;
+ padding: 0;
+ position: absolute;
+ white-space: nowrap;
+ width: 1px;
+ /* 1 */
+}
+
+/*
+ * Extends the .sr-only class to allow the element
+ * to be focusable when navigated to via the keyboard:
+ * https://www.drupal.org/node/897638
+ */
+
+.sr-only.focusable:active,
+.sr-only.focusable:focus {
+ clip: auto;
+ height: auto;
+ margin: 0;
+ overflow: visible;
+ position: static;
+ white-space: inherit;
+ width: auto;
+}
+
+/*
+ * Hide visually and from screen readers, but maintain layout
+ */
+
+.invisible {
+ visibility: hidden;
+}
+
+/*
+ * Clearfix: contain floats
+ *
+ * For modern browsers
+ * 1. The space content is one way to avoid an Opera bug when the
+ * `contenteditable` attribute is included anywhere else in the document.
+ * Otherwise it causes space to appear at the top and bottom of elements
+ * that receive the `clearfix` class.
+ * 2. The use of `table` rather than `block` is only necessary if using
+ * `:before` to contain the top-margins of child elements.
+ */
+
+.clearfix::before,
+.clearfix::after {
+ content: " ";
+ display: table;
+}
+
+.clearfix::after {
+ clear: both;
+}
+
+/* ==========================================================================
+ EXAMPLE Media Queries for Responsive Design.
+ These examples override the primary ('mobile first') styles.
+ Modify as content requires.
+ ========================================================================== */
+
+@media only screen and (min-width: 35em) {
+ /* Style adjustments for viewports that meet the condition */
+}
+
+@media print, (-webkit-min-device-pixel-ratio: 1.25), (min-resolution: 1.25dppx), (min-resolution: 120dpi) {
+ /* Style adjustments for high resolution devices */
+}
+
+/* ==========================================================================
+ Print styles.
+ Inlined to avoid the additional HTTP request:
+ https://www.phpied.com/delay-loading-your-print-css/
+ ========================================================================== */
+
+@media print {
+ *,
+ *::before,
+ *::after {
+ background: #fff !important;
+ color: #000 !important;
+ /* Black prints faster */
+ box-shadow: none !important;
+ text-shadow: none !important;
+ }
+
+ a,
+ a:visited {
+ text-decoration: underline;
+ }
+
+ a[href]::after {
+ content: " (" attr(href) ")";
+ }
+
+ abbr[title]::after {
+ content: " (" attr(title) ")";
+ }
+
+ /*
+ * Don't show links that are fragment identifiers,
+ * or use the `javascript:` pseudo protocol
+ */
+ a[href^="#"]::after,
+ a[href^="javascript:"]::after {
+ content: "";
+ }
+
+ pre {
+ white-space: pre-wrap !important;
+ }
+
+ pre,
+ blockquote {
+ border: 1px solid #999;
+ page-break-inside: avoid;
+ }
+
+ /*
+ * Printing Tables:
+ * https://web.archive.org/web/20180815150934/http://css-discuss.incutio.com/wiki/Printing_Tables
+ */
+ thead {
+ display: table-header-group;
+ }
+
+ tr,
+ img {
+ page-break-inside: avoid;
+ }
+
+ p,
+ h2,
+ h3 {
+ orphans: 3;
+ widows: 3;
+ }
+
+ h2,
+ h3 {
+ page-break-after: avoid;
+ }
+}
diff --git a/demo/src/static/css/normalize.css b/demo/src/static/css/normalize.css
new file mode 100644
index 0000000..192eb9c
--- /dev/null
+++ b/demo/src/static/css/normalize.css
@@ -0,0 +1,349 @@
+/*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */
+
+/* Document
+ ========================================================================== */
+
+/**
+ * 1. Correct the line height in all browsers.
+ * 2. Prevent adjustments of font size after orientation changes in iOS.
+ */
+
+html {
+ line-height: 1.15; /* 1 */
+ -webkit-text-size-adjust: 100%; /* 2 */
+}
+
+/* Sections
+ ========================================================================== */
+
+/**
+ * Remove the margin in all browsers.
+ */
+
+body {
+ margin: 0;
+}
+
+/**
+ * Render the `main` element consistently in IE.
+ */
+
+main {
+ display: block;
+}
+
+/**
+ * Correct the font size and margin on `h1` elements within `section` and
+ * `article` contexts in Chrome, Firefox, and Safari.
+ */
+
+h1 {
+ font-size: 2em;
+ margin: 0.67em 0;
+}
+
+/* Grouping content
+ ========================================================================== */
+
+/**
+ * 1. Add the correct box sizing in Firefox.
+ * 2. Show the overflow in Edge and IE.
+ */
+
+hr {
+ box-sizing: content-box; /* 1 */
+ height: 0; /* 1 */
+ overflow: visible; /* 2 */
+}
+
+/**
+ * 1. Correct the inheritance and scaling of font size in all browsers.
+ * 2. Correct the odd `em` font sizing in all browsers.
+ */
+
+pre {
+ font-family: monospace, monospace; /* 1 */
+ font-size: 1em; /* 2 */
+}
+
+/* Text-level semantics
+ ========================================================================== */
+
+/**
+ * Remove the gray background on active links in IE 10.
+ */
+
+a {
+ background-color: transparent;
+}
+
+/**
+ * 1. Remove the bottom border in Chrome 57-
+ * 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari.
+ */
+
+abbr[title] {
+ border-bottom: none; /* 1 */
+ text-decoration: underline; /* 2 */
+ text-decoration: underline dotted; /* 2 */
+}
+
+/**
+ * Add the correct font weight in Chrome, Edge, and Safari.
+ */
+
+b,
+strong {
+ font-weight: bolder;
+}
+
+/**
+ * 1. Correct the inheritance and scaling of font size in all browsers.
+ * 2. Correct the odd `em` font sizing in all browsers.
+ */
+
+code,
+kbd,
+samp {
+ font-family: monospace, monospace; /* 1 */
+ font-size: 1em; /* 2 */
+}
+
+/**
+ * Add the correct font size in all browsers.
+ */
+
+small {
+ font-size: 80%;
+}
+
+/**
+ * Prevent `sub` and `sup` elements from affecting the line height in
+ * all browsers.
+ */
+
+sub,
+sup {
+ font-size: 75%;
+ line-height: 0;
+ position: relative;
+ vertical-align: baseline;
+}
+
+sub {
+ bottom: -0.25em;
+}
+
+sup {
+ top: -0.5em;
+}
+
+/* Embedded content
+ ========================================================================== */
+
+/**
+ * Remove the border on images inside links in IE 10.
+ */
+
+img {
+ border-style: none;
+}
+
+/* Forms
+ ========================================================================== */
+
+/**
+ * 1. Change the font styles in all browsers.
+ * 2. Remove the margin in Firefox and Safari.
+ */
+
+button,
+input,
+optgroup,
+select,
+textarea {
+ font-family: inherit; /* 1 */
+ font-size: 100%; /* 1 */
+ line-height: 1.15; /* 1 */
+ margin: 0; /* 2 */
+}
+
+/**
+ * Show the overflow in IE.
+ * 1. Show the overflow in Edge.
+ */
+
+button,
+input { /* 1 */
+ overflow: visible;
+}
+
+/**
+ * Remove the inheritance of text transform in Edge, Firefox, and IE.
+ * 1. Remove the inheritance of text transform in Firefox.
+ */
+
+button,
+select { /* 1 */
+ text-transform: none;
+}
+
+/**
+ * Correct the inability to style clickable types in iOS and Safari.
+ */
+
+button,
+[type="button"],
+[type="reset"],
+[type="submit"] {
+ -webkit-appearance: button;
+}
+
+/**
+ * Remove the inner border and padding in Firefox.
+ */
+
+button::-moz-focus-inner,
+[type="button"]::-moz-focus-inner,
+[type="reset"]::-moz-focus-inner,
+[type="submit"]::-moz-focus-inner {
+ border-style: none;
+ padding: 0;
+}
+
+/**
+ * Restore the focus styles unset by the previous rule.
+ */
+
+button:-moz-focusring,
+[type="button"]:-moz-focusring,
+[type="reset"]:-moz-focusring,
+[type="submit"]:-moz-focusring {
+ outline: 1px dotted ButtonText;
+}
+
+/**
+ * Correct the padding in Firefox.
+ */
+
+fieldset {
+ padding: 0.35em 0.75em 0.625em;
+}
+
+/**
+ * 1. Correct the text wrapping in Edge and IE.
+ * 2. Correct the color inheritance from `fieldset` elements in IE.
+ * 3. Remove the padding so developers are not caught out when they zero out
+ * `fieldset` elements in all browsers.
+ */
+
+legend {
+ box-sizing: border-box; /* 1 */
+ color: inherit; /* 2 */
+ display: table; /* 1 */
+ max-width: 100%; /* 1 */
+ padding: 0; /* 3 */
+ white-space: normal; /* 1 */
+}
+
+/**
+ * Add the correct vertical alignment in Chrome, Firefox, and Opera.
+ */
+
+progress {
+ vertical-align: baseline;
+}
+
+/**
+ * Remove the default vertical scrollbar in IE 10+.
+ */
+
+textarea {
+ overflow: auto;
+}
+
+/**
+ * 1. Add the correct box sizing in IE 10.
+ * 2. Remove the padding in IE 10.
+ */
+
+[type="checkbox"],
+[type="radio"] {
+ box-sizing: border-box; /* 1 */
+ padding: 0; /* 2 */
+}
+
+/**
+ * Correct the cursor style of increment and decrement buttons in Chrome.
+ */
+
+[type="number"]::-webkit-inner-spin-button,
+[type="number"]::-webkit-outer-spin-button {
+ height: auto;
+}
+
+/**
+ * 1. Correct the odd appearance in Chrome and Safari.
+ * 2. Correct the outline style in Safari.
+ */
+
+[type="search"] {
+ -webkit-appearance: textfield; /* 1 */
+ outline-offset: -2px; /* 2 */
+}
+
+/**
+ * Remove the inner padding in Chrome and Safari on macOS.
+ */
+
+[type="search"]::-webkit-search-decoration {
+ -webkit-appearance: none;
+}
+
+/**
+ * 1. Correct the inability to style clickable types in iOS and Safari.
+ * 2. Change font properties to `inherit` in Safari.
+ */
+
+::-webkit-file-upload-button {
+ -webkit-appearance: button; /* 1 */
+ font: inherit; /* 2 */
+}
+
+/* Interactive
+ ========================================================================== */
+
+/*
+ * Add the correct display in Edge, IE 10+, and Firefox.
+ */
+
+details {
+ display: block;
+}
+
+/*
+ * Add the correct display in all browsers.
+ */
+
+summary {
+ display: list-item;
+}
+
+/* Misc
+ ========================================================================== */
+
+/**
+ * Add the correct display in IE 10+.
+ */
+
+template {
+ display: none;
+}
+
+/**
+ * Add the correct display in IE 10.
+ */
+
+[hidden] {
+ display: none;
+}
diff --git a/demo/src/static/favicon.png b/demo/src/static/favicon.png
new file mode 100644
index 0000000..50f1960
Binary files /dev/null and b/demo/src/static/favicon.png differ
diff --git a/demo/src/static/img/Liveness-woman.png b/demo/src/static/img/Liveness-woman.png
new file mode 100644
index 0000000..0982aa3
Binary files /dev/null and b/demo/src/static/img/Liveness-woman.png differ
diff --git a/demo/src/static/img/No-not-worked-woman-yellow.png b/demo/src/static/img/No-not-worked-woman-yellow.png
new file mode 100644
index 0000000..6675d9e
Binary files /dev/null and b/demo/src/static/img/No-not-worked-woman-yellow.png differ
diff --git a/demo/src/static/img/arrow-right.svg b/demo/src/static/img/arrow-right.svg
new file mode 100644
index 0000000..f8dc046
--- /dev/null
+++ b/demo/src/static/img/arrow-right.svg
@@ -0,0 +1,3 @@
+
+
+
+
+ Web SDK Demo
+
+
+
Demo page for iProov Web integrators. Enter your email address, select claim mode, and iProov!
+
+
+
+
+
+
+
+
+
diff --git a/demo/src/static/js/iproov-integration.js b/demo/src/static/js/iproov-integration.js
new file mode 100644
index 0000000..32530cb
--- /dev/null
+++ b/demo/src/static/js/iproov-integration.js
@@ -0,0 +1,35 @@
+export const IPROOV_EVENTS = [
+ "cancelled",
+ "error",
+ "failed",
+ "interrupted",
+ "multiple_cameras",
+ "passed",
+ "permission",
+ "permission_denied",
+ "progress",
+ "ready",
+ "started",
+ "streaming",
+ "streamed",
+ "unsupported",
+]
+
+export function createSDK(logger, token, base_url) {
+ const template = document.querySelector("#iproov_template").content.cloneNode(true)
+ const iProov = document.createElement("iproov-me")
+ iProov.setAttribute("token", token)
+ iProov.setAttribute("base_url", base_url)
+ iProov.addEventListener("progress", (event) => {
+ const { progress, message } = event.detail
+ document.querySelector(".progress__inner").style.width = progress + '%'
+ document.querySelector(".progress__text").innerText = message
+ })
+ iProov.append(template)
+ IPROOV_EVENTS.forEach((eventName) => {
+ iProov.addEventListener(eventName, (event) => {
+ logger.log(`Captured ${event.type} event:`, event.detail)
+ })
+ })
+ return iProov
+}
diff --git a/demo/src/static/js/main.js b/demo/src/static/js/main.js
new file mode 100644
index 0000000..e1a0557
--- /dev/null
+++ b/demo/src/static/js/main.js
@@ -0,0 +1,139 @@
+import "./vendor/prod/iProovSupport.js"
+
+import { createSDK } from "./iproov-integration.js"
+
+/**
+ * Dispatch a request to the demo backend to create a new token.
+ * Initialize a new SDK instance or handle any errors.
+ */
+async function submitTokenRequest() {
+ const formData = new FormData(document.querySelector("#token_config"))
+ const payload = {}
+ for (let [field, value] of formData.entries()) {
+ payload[field] = value
+ }
+ const res = await fetch(`/api/claim/${payload.mode}/token`, {
+ method: "POST",
+ headers: { "content-type": "application/json" },
+ body: JSON.stringify(payload),
+ })
+ const body = await res.json()
+ if (body.error) {
+ return handleError(body)
+ }
+ document.querySelector("#token_config .error-container").classList.add("hidden")
+ return initializeSDK(body)
+}
+
+/**
+ * Prepare the form for another submission.
+ */
+async function resetTokenCreationForm() {
+ document.querySelector("#token_config").classList.remove("collapsed")
+ document.querySelector("#iproov_wrapper").classList.add("hidden")
+ document.querySelector("#user_id").focus()
+}
+
+/**
+ * On load, restore any cached user_id. If a user_id exists, automatically set the mode to verify.
+ * On change, cache the user_id to localStorage.
+ */
+function primeForm() {
+ const userIDField = document.querySelector("#user_id")
+ const verifyRadio = document.querySelector("input[name=mode][value=verify]")
+ let cachedUserId = localStorage.getItem("user_id")
+ if (cachedUserId) {
+ userIDField.value = cachedUserId
+ verifyRadio.setAttribute("checked", true)
+ }
+ userIDField.addEventListener("change", function cacheUserId() {
+ localStorage.setItem("user_id", userIDField.value)
+ })
+}
+
+/**
+ * Create a standalone support checker instance and configure the page to respond to basic checks.
+ * @return {iProovSupport}
+ */
+function createSupportChecker() {
+ const checker = new iProovSupport.iProovSupport() // vanilla JS with no webpack/UMD
+ const output = document.querySelector(".support-container")
+ checker.addEventListener("granted", (event) => {
+ console.log("Permission is granted")
+ })
+ checker.addEventListener("denied", (event) => {
+ console.warn("Permission denied", event)
+ handleError(createError("permission_denied", "Device permission was denied"))
+ })
+ checker.addEventListener("check", (event) => {
+ const { supported, granted } = event.detail
+ output.innerHTML = `Device supported: ${supported.toString()}; permission granted: ${granted}`
+
+ if (!supported || granted === false) {
+ output.classList.remove("support-container--ok")
+ output.classList.add("support-container--error")
+ } else if (supported) {
+ output.classList.add("support-container--ok")
+ output.classList.remove("support-container--error")
+ }
+
+ output.classList.remove("hidden")
+ })
+ checker.check()
+ return checker
+}
+
+/**
+ * Create a new SDK instance, customise it (see iproov-integration.js) and append to the page.
+ * @param body
+ */
+async function initializeSDK(body) {
+ const { token, base_url } = body
+ const iProov = createSDK(console, token, base_url)
+ const container = document.querySelector("#iproovme_container")
+ container.innerHTML = ""
+ container.appendChild(iProov)
+ if (!initializeSDK.imported) {
+ await import("../node_modules/@iproov/web/iProovMe.js")
+ initializeSDK.imported = true
+ }
+ const wrapper = document.querySelector("#iproov_wrapper")
+ wrapper.classList.remove("hidden")
+ iProov.addEventListener("ready", () => {
+ iProov.querySelector("[slot=button] button").focus()
+ wrapper.scrollIntoView({ behavior: "smooth", block: "end" })
+ })
+ document.querySelector("#token_config").classList.add("collapsed")
+}
+
+initializeSDK.imported = false
+
+function createError(title, description) {
+ return { error: title, error_description: description }
+}
+
+function handleError(body) {
+ const errorContainer = document.querySelector("#token_config .error-container")
+ errorContainer.innerHTML = `