nent-styles { .silk-horizontal-divider { border-top: 1px solid var(--silk-divider-color, var(--silk-border-color)); width: 100%; }}@layer component-styles { .silk-vertical-divider { border-left: 1px solid var(--silk-divider-color, var(--silk-border-color)); height: var(--silk-divider-length, 90%); }}@layer component-styles { .silk-switch { position: relative; }}@layer component-styles { .silk-switch-track { width: var(--silk-switch-track-width); min-width: var(--silk-switch-track-width); height: var(--silk-switch-track-height); min-height: var(--silk-switch-track-height); padding: var(--silk-switch-track-padding); border-radius: var(--silk-switch-border-radius, 9999px); background-color: var(--silk-switch-track-background-color); transition: background-color var(--silk-switch-transition-duration, var(--silk-transition-duration-fast, 150ms)); box-sizing: content-box; }}@layer component-styles { .silk-switch-track:hover:not([aria-disabled="true"]) { cursor: pointer; }}@layer component-styles { .silk-switch-thumb { width: var(--silk-switch-track-height); height: var(--silk-switch-track-height); border-radius: var(--silk-switch-border-radius, 9999px); background-color: var(--silk-switch-thumb-color); translate: var(--silk-switch-thumb-offset); transition: translate var(--silk-switch-transition-duration, var(--silk-transition-duration-fast, 150ms)); }}@layer component-styles { .silk-tabs-tab-row { width: 100%; border-bottom: var(--silk-tab-border-thickness, 2px) solid var(--silk-tab-border-color, var(--silk-border-color)); }}@layer component-styles { .silk-tabs-tab { cursor: pointer; transition: background-color var(--silk-tab-color-transition-duration, var(--silk-transition-duration-normal, 200ms)), color var(--silk-tab-color-transition-duration, var(--silk-transition-duration-normal, 200ms)), border-color var(--silk-tab-color-transition-duration, var(--silk-transition-duration-normal, 200ms)); background-color: var(--silk-tab-background-color); color: var(--silk-tab-color); user-select: none; padding: 0.5rem; margin: 0px 0px calc(-1 * var(--silk-tab-border-thickness, 2px)); border-bottom: var(--silk-tab-border-thickness, 2px) solid var(--silk-tab-border-color, var(--silk-border-color)); }}@layer component-styles { .silk-tabs-tab[aria-disabled="true"] { background-color: var(--silk-tab-disabled-background-color); cursor: not-allowed; }}@layer component-styles { .silk-tabs-tab:hover:not([aria-disabled="true"]) { background-color: var(--silk-tab-hover-background-color); }}@layer component-styles { .silk-tabs-tab:active:not([aria-disabled="true"]) { background-color: var(--silk-tab-pressed-background-color); }}@layer component-styles { .silk-tabs-panel { padding: 1rem; width: 100%; flex-grow: 1; overflow-y: auto; }}@layer component-styles { .silk-tooltip-arrow { position: absolute; border-width: 5px; border-style: solid; }}@layer component-styles { .silk-tooltip { position: relative; background-color: var(--silk-tooltip-background-color); color: var(--silk-tooltip-color); border-radius: 6px; }}@layer component-styles { .silk-tooltip-text { padding: 5px; }}@layer restricted-styles { .silk-button-size_xs { --silk-button-font-size: var(--silk-font-size-xs, 0.75rem); --silk-button-height: 1.5rem; --silk-button-padding-horizontal: 0.5rem; }}@layer restricted-styles { .silk-button-size_sm { --silk-button-font-size: var(--silk-font-size-sm, 0.875rem); --silk-button-height: 2rem; --silk-button-padding-horizontal: 0.75rem; }}@layer restricted-styles { .silk-button-size_md { --silk-button-font-size: var(--silk-font-size-md, 1rem); --silk-button-height: 2.5rem; --silk-button-padding-horizontal: 1rem; }}@layer restricted-styles { .silk-button-size_lg { --silk-button-font-size: var(--silk-font-size-lg, 1.125rem); --silk-button-height: 3rem; --silk-button-padding-horizontal: 1.5rem; }}@layer restricted-styles { .silk-checkbox-size_sm { --silk-checkbox-size: 0.875rem; --silk-checkbox-icon-size: 0.45rem; --silk-checkbox-font-size: var(--silk-font-size-sm, 0.875rem); }}@layer restricted-styles { .silk-checkbox-size_md { --silk-checkbox-size: 1rem; --silk-checkbox-icon-size: 0.625rem; --silk-checkbox-font-size: var(--silk-font-size-md, 1rem); }}@layer restricted-styles { .silk-checkbox-size_lg { --silk-checkbox-size: 1.25rem; --silk-checkbox-icon-size: 0.8rem; --silk-checkbox-font-size: var(--silk-font-size-lg, 1.125rem); }}@layer restricted-styles { .silk-input-size_xs { --silk-input-font-size: var(--silk-font-size-xs, 0.75rem); --silk-input-height: 1.25rem; --silk-input-padding: 0.375rem; --silk-input-border-radius: var(--silk-border-radius-xs, 0.125rem); }}@layer restricted-styles { .silk-input-size_sm { --silk-input-font-size: var(--silk-font-size-sm, 0.875rem); --silk-input-height: 1.75rem; --silk-input-padding: 0.5rem; --silk-input-border-radius: var(--silk-border-radius-sm, 0.25rem); }}@layer restricted-styles { .silk-input-size_md { --silk-input-font-size: var(--silk-font-size-md, 1rem); --silk-input-height: 2.25rem; --silk-input-padding: 0.625rem; --silk-input-border-radius: var(--silk-border-radius-md, 0.375rem); }}@layer restricted-styles { .silk-input-size_lg { --silk-input-font-size: var(--silk-font-size-lg, 1.125rem); --silk-input-height: 2.5rem; --silk-input-padding: 0.75rem; --silk-input-border-radius: var(--silk-border-radius-md, 0.375rem); }}@layer restricted-styles { .silk-switch-size_sm { --silk-switch-track-width: 1.375rem; --silk-switch-track-height: 0.75rem; --silk-switch-track-padding: 0.188rem; }}@layer restricted-styles { .silk-switch-size_md { --silk-switch-track-width: 1.875rem; --silk-switch-track-height: 1rem; --silk-switch-track-padding: 0.188rem; }}@layer restricted-styles { .silk-switch-size_lg { --silk-switch-track-width: 2.875rem; --silk-switch-track-height: 1.5rem; --silk-switch-track-padding: 0.188rem; }}@layer restricted-styles { .silk-callout-type_caution_light { --silk-callout-color: rgb(220, 20, 60); --silk-callout-background-color: rgba(220, 20, 60, 0.14901960784313725); }}@layer restricted-styles { .silk-callout-type_caution_dark { --silk-callout-color: rgb(255, 0, 0); --silk-callout-background-color: rgba(255, 0, 0, 0.2); }}@layer restricted-styles { .silk-callout-type_important_light { --silk-callout-color: rgb(153, 50, 204); --silk-callout-background-color: rgba(153, 50, 204, 0.14901960784313725); }}@layer restricted-styles { .silk-callout-type_important_dark { --silk-callout-color: rgb(153, 50, 204); --silk-callout-background-color: rgba(153, 50, 204, 0.2); }}@layer restricted-styles { .silk-callout-type_note_light { --silk-callout-color: rgb(30, 144, 255); --silk-callout-background-color: rgba(30, 144, 255, 0.14901960784313725); }}@layer restricted-styles { .silk-callout-type_note_dark { --silk-callout-color: rgb(30, 144, 255); --silk-callout-background-color: rgba(30, 144, 255, 0.2); }}@layer restricted-styles { .silk-callout-type_question_light { --silk-callout-color: rgb(46, 139, 87); --silk-callout-background-color: rgba(46, 139, 87, 0.14901960784313725); }}@layer restricted-styles { .silk-callout-type_question_dark { --silk-callout-color: rgb(127, 255, 212); --silk-callout-background-color: rgba(127, 255, 212, 0.2); }}@layer restricted-styles { .silk-callout-type_quote_light { --silk-callout-color: rgb(128, 128, 128); --silk-callout-background-color: rgba(128, 128, 128, 0.14901960784313725); }}@layer restricted-styles { .silk-callout-type_quote_dark { --silk-callout-color: rgb(128, 128, 128); --silk-callout-background-color: rgba(128, 128, 128, 0.2); }}@layer restricted-styles { .silk-callout-type_tip_light { --silk-callout-color: rgb(50, 205, 50); --silk-callout-background-color: rgba(50, 205, 50, 0.14901960784313725); }}@layer restricted-styles { .silk-callout-type_tip_dark { --silk-callout-color: rgb(50, 205, 50); --silk-callout-background-color: rgba(50, 205, 50, 0.2); }}@layer restricted-styles { .silk-callout-type_warning_light { --silk-callout-color: rgb(255, 140, 0); --silk-callout-background-color: rgba(255, 140, 0, 0.14901960784313725); }}@layer restricted-styles { .silk-callout-type_warning_dark { --silk-callout-color: rgb(255, 165, 0); --silk-callout-background-color: rgba(255, 165, 0, 0.2); }}@layer component-styles { .silk-link { text-decoration-line: none; }}@layer component-styles { .silk-link:link { color: var(--silk-link-default-color); }}@layer component-styles { .silk-link:visited { color: var(--silk-link-visited-color); }}@layer component-styles { .silk-link:hover { text-decoration-line: underline; }}@layer component-styles { .silk-toc { list-style-type: none; text-align: start; padding: 0rem; }}@layer general-styles { .headline-text { font-size: 2rem; text-align: start; line-height: 1.2; }}@media (min-width: 48rem) { @layer general-styles { .headline-text { font-size: 3rem; }}}@layer general-styles { .subheadline-text_light { font-size: 1.5rem; text-align: start; color: rgba(0, 0, 0, 0.8); }}@layer general-styles { .subheadline-text_dark { font-size: 1.5rem; text-align: start; color: rgba(255, 255, 255, 0.8); }}@media (min-width: 48rem) { @layer general-styles { .subheadline-text { font-size: 2rem; }}}@layer general-styles { .markdown h1 { color: rgb(0, 192, 176); font-size: 2rem; font-weight: 400; margin: 0px 0px 2.5rem; line-height: 1.2; }}@media (min-width: 48rem) { @layer general-styles { .markdown h1 { font-size: 2.5rem; }}}@layer general-styles { .markdown h2 { color: rgb(0, 192, 176); font-size: 1.75rem; font-weight: 300; margin: 2rem 0px; }}@media (min-width: 48rem) { @layer general-styles { .markdown h2 { font-size: 2.2rem; }}}@layer general-styles { .markdown h3 { font-size: 1.6rem; font-weight: 300; margin: 1.5rem 0px; }}@media (min-width: 48rem) { @layer general-styles { .markdown h3 { font-size: 2.1rem; }}}@layer general-styles { .markdown h4 { font-size: 1rem; font-weight: bolder; margin: 1rem 0px 0.5rem; }}@layer general-styles { .markdown p { font-size: 1.2rem; margin: 0px 0px 0.8rem; }}@media (min-width: 48rem) { @layer general-styles { .markdown p { font-size: 1.5rem; }}}@layer general-styles { .markdown hr { border: 2px solid rgb(255, 215, 0); }}@layer general-styles { .markdown ul { width: 100%; overflow-wrap: break-word; }}@layer general-styles { .markdown li, ol, ul { font-size: 1.2rem; margin: 0px 0px 0.75rem; }}@media (min-width: 48rem) { @layer general-styles { .markdown li, ol, ul { font-size: 1.5rem; }}}@layer general-styles { .markdown_light code { color: rgba(0, 0, 0, 0.8); font-weight: bolder; }}@layer general-styles { .markdown_dark code { color: rgba(255, 255, 255, 0.8); font-weight: bolder; }}@layer general-styles { .markdown pre { margin: 0.5rem 0px 2rem; width: 100%; }}@layer general-styles { .markdown_light pre > code { display: block; width: 100%; background-color: rgb(244, 246, 250); border: 1px solid rgb(0, 0, 0); border-radius: 0.25rem; padding: 0.5rem; font-size: 1rem; overflow-x: auto; }}@layer general-styles { .markdown_dark pre > code { display: block; width: 100%; background-color: rgb(19, 23, 31); border: 1px solid rgb(255, 255, 255); border-radius: 0.25rem; padding: 0.5rem; font-size: 1rem; overflow-x: auto; }}@layer general-styles { .markdown_light img { display: block; width: 100%; background-color: rgb(244, 246, 250); border: 2px solid rgb(70, 70, 79); border-radius: 0.25rem; padding: 0.5rem; font-size: 1rem; overflow-x: auto; }}@layer general-styles { .markdown_dark img { display: block; width: 100%; background-color: rgb(19, 23, 31); border: 2px solid rgb(70, 70, 79); border-radius: 0.25rem; padding: 0.5rem; font-size: 1rem; overflow-x: auto; }}@layer general-styles { .markdown .pc30-width { width: 30%; }}@layer general-styles { .markdown .align-centre { align-self: center; }}@layer general-styles { .markdown .extra-narrow-port { width: 50%; }}@media (min-width: 48rem) { @layer general-styles { .markdown .extra-narrow-port { width: 25%; }}}@layer general-styles { .markdown .narrow-port { width: 75%; }}@media (min-width: 48rem) { @layer general-styles { .markdown .narrow-port { width: 40%; }}}@layer general-styles { .page-content { width: 100%; height: 100%; padding: 2rem 2rem 0px; }}@media (min-width: 48rem) { @layer general-styles { .page-content { max-width: 70rem; }}}@layer general-styles { .footer_light { font-size: 1rem; background-color: rgb(244, 246, 250); padding: 1.5rem 10%; }}@layer general-styles { .footer_dark { font-size: 1rem; background-color: rgb(19, 23, 31); padding: 1.5rem 10%; }}@layer general-styles { .nav-header { width: 100%; padding: 1rem; }}@layer general-styles { .form-button_light { width: 100px; height: 40px; font-weight: 600; color: rgb(6, 0, 108); background: rgb(225, 224, 255); border-color: rgb(6, 0, 108); transition: background 500ms; }}@layer general-styles { .form-button_dark { width: 100px; height: 40px; font-weight: 600; color: rgb(225, 224, 255); background: rgb(0, 128, 128); border-color: rgb(225, 224, 255); transition: background 500ms; }}@media (min-width: 48rem) { @layer general-styles { .form-button { width: 120px; font-size: x-large; }}}@layer general-styles { .form-button_light:hover { color: rgb(0, 33, 20); background: rgb(120, 250, 195); box-shadow: rgb(0, 0, 0) 5px 5px 10px; border-width: 0px; }}@layer general-styles { .form-button_dark:hover { color: rgb(120, 250, 195); background: rgb(0, 81, 56); box-shadow: rgb(0, 0, 0) 5px 5px 10px; border-width: 0px; }}@layer general-styles { .form-input:focus { border-width: 2px; border-color: rgb(33, 23, 227); box-shadow: 0px 0px; color: rgb(33, 23, 227); }}@layer general-styles { .form-labels_light { color: rgb(0, 0, 0); padding: 0px 0px 0px 5px; margin: 10px 0px 0px; text-align: start; }}@layer general-styles { .form-labels_dark { color: rgb(225, 224, 255); padding: 0px 0px 0px 5px; margin: 10px 0px 0px; text-align: start; }}@layer general-styles { .form-check-label_light { width: 100%; color: rgb(0, 0, 0); padding: 0px 0px 0px 8px; text-align: start; }}@layer general-styles { .form-check-label_dark { width: 100%; color: rgb(225, 224, 255); padding: 0px 0px 0px 8px; text-align: start; }}@layer general-styles { .check-box_light { border: 2px solid rgb(6, 0, 108); box-shadow: 0px 0px; }}@layer general-styles { .check-box_dark { border: 2px solid rgb(225, 224, 255); box-shadow: 0px 0px; }}@layer general-styles { .check-box:checked { border: 0px; box-shadow: 0px 0px; color: rgb(0, 0, 0); background-color: rgb(0, 33, 20); }}@layer general-styles { .contact-form_light { width: 100%; border-radius: 10px; background-color: rgb(225, 224, 255); padding: 5px; }}@layer general-styles { .contact-form_dark { width: 100%; border-radius: 10px; background-color: rgb(0, 128, 128); padding: 5px; }}@media (min-width: 48rem) { @layer general-styles { .contact-form { padding: 20px; }}}@layer general-styles { .p-contact-form_light { padding: 10px 0px 0px; width: 100%; text-align: center; font-size: larger; font-weight: 600; color: rgb(0, 0, 0); }}@layer general-styles { .p-contact-form_dark { padding: 10px 0px 0px; width: 100%; text-align: center; font-size: larger; font-weight: 600; color: rgb(225, 224, 255); }}@media (min-width: 48rem) { @layer general-styles { .p-contact-form { font-size: x-large; }}}@layer general-styles { .hero-container { width: 100%; gap: 4rem; }}@media (min-width: 48rem) { @layer general-styles { .hero-container { margin-top: 10vh; }}}@layer general-styles { .link-base_light { color: rgb(6, 0, 108); font-weight: 600; font-size: large; text-decoration-line: none; transition: color 200ms; }}@layer general-styles { .link-base_dark { color: rgb(225, 224, 255); font-weight: 600; font-size: large; text-decoration-line: none; transition: color 200ms; }}@layer general-styles { .link-base_light:any-link { color: rgb(6, 0, 108); font-weight: 600; text-decoration-line: none; }}@layer general-styles { .link-base_dark:any-link { color: rgb(225, 224, 255); font-weight: 600; text-decoration-line: none; }}@layer general-styles { .link-base_light:hover { color: rgb(120, 250, 195); }}@layer general-styles { .link-base_dark:hover { color: rgb(252, 226, 101); }}@layer general-styles { .nav-item { color: rgb(6, 0, 108); font-weight: 600; font-size: large; text-decoration-line: none; transition: color 200ms; }}@layer general-styles { .nav-item:any-link { color: rgb(6, 0, 108); font-weight: 600; text-decoration-line: none; }}@layer general-styles { .nav-item:hover { color: rgb(33, 27, 0); }}@layer general-styles { .nav { width: 100%; display: flex; font-weight: 600; font-size: large; justify-content: space-between; }}@layer general-styles { .nav.navbar { display: flex; }}@layer general-styles { .nav.nav-bar .navbaritem { list-style-type: none; border-radius: 10px; padding: 0px 20px; }}@layer general-styles { .nav.navbar .navbaritem .dropdown { position: absolute; display: none; top: 100%; right: 0px; overflow-y: hidden; }}@layer general-styles { .nav.dropdown .services { position: absolute; right: -100px; width: max-content; background-color: rgb(255, 251, 255); padding: 5px; border-radius: 10px; height: 0px; overflow: hidden; visibility: hidden; }}@layer general-styles { .nav.dropdown:hover .services { height: min-content; margin: 60px 0px 0px; visibility: visible; overflow: hidden; }}@layer general-styles { .nav.navbar .dropdown:hover .services { height: min-content; margin: 20px 0px 0px; visibility: visible; overflow: hidden; }}@layer general-styles { .nav.dropdown .services .dropitems { top: 100%; margin: 0px 0px 5px; }}@layer general-styles { .nav.navbar .dropdown::after { content: ""; position: absolute; right: -5px; top: 8px; cursor: pointer; transform: rotate(-45deg); border-left: 2px solid rgb(0, 0, 0); border-bottom: 2px solid rgb(0, 0, 0); transition: 0.2s ease-in; width: 7px; height: 7px; }}@layer general-styles { .nav.navbar .dropdown:hover::after { transform: rotate(135deg); }}@layer component-variants { .silk-input-outlined { padding-inline: var(--silk-input-padding) var(--silk-input-padding); border-radius: var(--silk-input-border-radius); border: 1px solid var(--silk-input-border-color, var(--silk-border-color)); }}@layer component-variants { .silk-input-outlined[aria-invalid="true"] { border: 1px solid var(--silk-input-border-invalid-color); box-shadow: 0px 0px 0 1px var(--silk-input-border-invalid-color); }}@layer component-variants { .silk-input-outlined:hover:not(:disabled) { border-color: var(--silk-input-border-hover-color); }}@layer component-variants { .silk-input-outlined:focus-visible:not(:disabled) { border: 1px solid var(--silk-input-border-focus-color, var(--silk-focus-outline-color)); box-shadow: 0px 0px 0 1px var(--silk-input-border-focus-color, var(--silk-focus-outline-color)); }}@layer component-variants { .silk-input-filled { padding-inline: var(--silk-input-padding) var(--silk-input-padding); background-color: var(--silk-input-filled-color); border-radius: var(--silk-input-border-radius); border: 1px solid rgba(0, 0, 0, 0); }}@layer component-variants { .silk-input-filled:hover:not(:disabled) { background-color: var(--silk-input-filled-hover-color); }}@layer component-variants { .silk-input-filled[aria-invalid="true"] { border-color: var(--silk-input-border-invalid-color); box-shadow: 0px 0px 0 1px var(--silk-input-border-invalid-color); }}@layer component-variants { .silk-input-filled:focus-visible:not(:disabled) { background-color: var(--silk-input-filled-focus-color); border-color: var(--silk-input-border-focus-color, var(--silk-focus-outline-color)); box-shadow: 0px 0px 0 1px var(--silk-input-border-focus-color, var(--silk-focus-outline-color)); }}@layer component-variants { .silk-input-flushed { border-bottom: 1px solid var(--silk-input-border-color, var(--silk-border-color)); }}@layer component-variants { .silk-input-flushed[aria-invalid="true"] { border-color: var(--silk-input-border-invalid-color); box-shadow: 0px 1px var(--silk-input-border-invalid-color); }}@layer component-variants { .silk-input-flushed:hover:not(:disabled) { border-color: var(--silk-input-border-hover-color); }}@layer component-variants { .silk-input-flushed:focus-visible:not(:disabled) { border-color: var(--silk-input-border-focus-color, var(--silk-focus-outline-color)); box-shadow: 0px 1px var(--silk-input-border-focus-color, var(--silk-focus-outline-color)); }}@layer component-variants { .silk-callout-left-bordered { border-left: 0.25em solid var(--silk-callout-color); padding: 0.5rem 1rem; }}@layer component-variants { .silk-callout-left-bordered > .callout-title { color: var(--silk-callout-color); margin-bottom: 1rem; }}@layer component-variants { .silk-callout-left-bordered > .callout-body > p:last-child { margin-block-end: 0px; }}@layer component-variants { .silk-callout-left-bordered-filled { border-left: 0.25em solid var(--silk-callout-color); background-color: var(--silk-callout-background-color); border-radius: 4px; padding: 0.8rem; box-shadow: rgba(0, 0, 0, 0.118) 0px 1px 2px, rgba(0, 0, 0, 0.08) 0px 3px 10px; }}@layer component-variants { .silk-callout-left-bordered-filled > .callout-title { color: var(--silk-callout-color); margin-bottom: 0.25rem; }}@layer component-variants { .silk-callout-left-bordered-filled > .callout-body > p:last-child { margin-block-end: 0px; }}@layer component-variants { .silk-callout-outlined { border: 1px solid var(--silk-callout-color); border-radius: 0.2rem; }}@layer component-variants { .silk-callout-outlined > .callout-title { background-color: var(--silk-callout-background-color); padding: 0.5rem 0.75rem; }}@layer component-variants { .silk-callout-outlined .callout-icon { color: var(--silk-callout-color); }}@layer component-variants { .silk-callout-outlined > .callout-body { padding: 0.5rem 0.75rem; }}@layer component-variants { .silk-callout-outlined > .callout-body > p:last-child { margin-block-end: 0px; }}@layer component-variants { .silk-callout-matching-link :is(:any-link) { color: var(--silk-callout-color); }}@layer component-variants { .silk-input-checkbox { border: 0px; width: 1px; height: 1px; margin: -1px; padding: 0px; clip-path: inset(50%); overflow: hidden; white-space: nowrap; position: absolute; }}@layer component-variants { .silk-input-checkbox:focus-visible + * { box-shadow: 0px 0px 0 var(--silk-checkbox-focus-outline-spread, 0.1875rem) var(--silk-checkbox-focus-outline-color, var(--silk-focus-outline-color)); }}@layer component-variants { .silk-input-checkbox:not([aria-disabled]):hover + * { --silk-checkbox-icon-background-color: var(--silk-checkbox-icon-background-hover-color); }}@layer component-variants { .silk-checkbox-icon-container-checked { background-color: var(--silk-checkbox-icon-background-color); border-color: var(--silk-checkbox-icon-background-color); }}@layer component-variants { .silk-checkbox-icon-container-unchecked { background-color: var(--silk-checkbox-unchecked-background-color); }}@layer component-variants { .silk-input-switch { border: 0px; width: 1px; height: 1px; margin: -1px; padding: 0px; clip-path: inset(50%); overflow: hidden; white-space: nowrap; position: absolute; }}@layer component-variants { .silk-input-switch:focus-visible + * { box-shadow: 0px 0px 0 0.1875rem var(--silk-switch-focus-color, var(--silk-focus-outline-color)); }}@layer component-variants { .silk-tooltip-arrow-top-left { margin: -9px 0px 0px 9px; top: 0px; border-color: transparent transparent var(--silk-tooltip-background-color) transparent; }}@layer component-variants { .silk-tooltip-arrow-top { margin: -9px 0px 0px -5px; left: 50%; top: 0px; border-color: transparent transparent var(--silk-tooltip-background-color) transparent; }}@layer component-variants { .silk-tooltip-arrow-top-right { margin: -9px 9px 0px 0px; right: 0px; top: 0px; border-color: transparent transparent var(--silk-tooltip-background-color) transparent; }}@layer component-variants { .silk-tooltip-arrow-left-top { margin: 9px 0px 0px -9px; left: 0px; top: 0px; border-color: transparent var(--silk-tooltip-background-color) transparent transparent; }}@layer component-variants { .silk-tooltip-arrow-left { margin: -5px 0px 0px -9px; left: 0px; top: 50%; border-color: transparent var(--silk-tooltip-background-color) transparent transparent; }}@layer component-variants { .silk-tooltip-arrow-left-bottom { margin: 0px 0px 9px -9px; left: 0px; bottom: 0px; border-color: transparent var(--silk-tooltip-background-color) transparent transparent; }}@layer component-variants { .silk-tooltip-arrow-right-top { margin: 9px -9px 0px 0px; right: 0px; top: 0px; border-color: transparent transparent transparent var(--silk-tooltip-background-color); }}@layer component-variants { .silk-tooltip-arrow-right { margin: -5px -9px 0px 0px; right: 0px; top: 50%; border-color: transparent transparent transparent var(--silk-tooltip-background-color); }}@layer component-variants { .silk-tooltip-arrow-right-bottom { margin: 0px -9px 9px 0px; right: 0px; bottom: 0px; border-color: transparent transparent transparent var(--silk-tooltip-background-color); }}@layer component-variants { .silk-tooltip-arrow-bottom-left { margin: 0px 0px -9px 9px; left: 0px; bottom: 0px; border-color: var(--silk-tooltip-background-color) transparent transparent transparent; }}@layer component-variants { .silk-tooltip-arrow-bottom { margin: 0px 0px -9px -5px; left: 50%; bottom: 0px; border-color: var(--silk-tooltip-background-color) transparent transparent transparent; }}@layer component-variants { .silk-tooltip-arrow-bottom-right { margin: 0px 9px -9px 0px; right: 0px; bottom: 0px; border-color: var(--silk-tooltip-background-color) transparent transparent transparent; }}@layer component-variants { .silk-image-fit-width { width: 100%; object-fit: scale-down; }}@layer component-variants { .silk-link-uncolored:link { color: var(--silk-color); }}@layer component-variants { .silk-link-uncolored:visited { color: var(--silk-color); }}@layer component-variants { .silk-link-undecorated:hover { text-decoration-line: none; }}@layer component-variants { .silk-link-always-underlined { text-decoration-line: underline; }}@layer component-variants { .silk-toc-bordered { border-radius: 5px; border: 1px solid var(--silk-toc-border-color, var(--silk-border-color)); padding: 1rem; }}@layer component-variants { .silk-button-circle { padding: 0px; border-radius: 50%; }}@layer component-variants { .silk-button-uncolored { --silk-button-background-default-color: rgba(0, 0, 0, 0); }}
Some Examples of Bespoke Software Projects
Running Gait Skeletal Tracking. RUNRIGHT
- Created a system that automatically measures the running gait of an athlete.
- Gigabytes of data to results in seconds from multi-threaded C++ and asynchronous processes
- Superior accuracy achieved by synchronising multiple cameras and in house skeletal tracker
- Custom Yocto Linux and WiFi direct provides robustness, OTA updates and remote support.
- Java diagnostic client provides ease of debugging and access to all raw metrics
- Displays a browsable 3D OpenGL world view of point cloud data
Running Gait Analysis Android App
- Android App runs on a tablet and connects to the running gait cameras via WiFi Direct
- Built using best practices with Kotlin, Jetpack compose, coroutines and asynchronous flows.
- Low level canvas methods used to create some re-usable elegant animated custom dials.
Crane Simulator Mathematical Model
-
C# model that provides a true to life simulation for training offshore crane operators.
-
Advanced physics (Inertia tensors, 3-D kinematics, PID control loops, ray tracing)
-
Includes wind shear, shadows, load imbalance, rope collision, sling failure, boom flex, buoyancy, water resistance, tidal flow etc.
HiTech Gym Equipment
- Designed the proprietary electronics and firmware for wireless force plates used to train and condition professional athletes.
- BeagleBone SBC runs custom yocto Linux for a fast boot and ease of updates.
- WiFi direct used to interface to an Android controller App.
Visualisation of Digital Acoustic Sensing data
- Provided contract programing for an Acoustic Sensing App in the Oil Field Services sector
- Java and Agile methods employed to enhance various DSP modules in the processing chain (Decimation, IIR Filters, FFT, de-striping etc).
- Ported and enhanced a Machine Learning model for tracking trains from Python Keras TensorFlow to Java using the DeepLearning4J library.
- Transcribed various algorithms from Matlab to Java to boost performance by several times.
3rd Party Code Reviews for Medical Instrumentation Firmware
- Provide independent code reviews for medical instrument suppliers
- Early identification of issues avoids embarrassing and expensive mistakes reaching production.
Phased Array Radar Vector Math Library
- Helped design and implement the architecture for a phased array radar DSP.
- Beowulf cluster of COTS multi-core Linux PCs connected via InfiniBand.
- Design goals of maximum data throughput with minimal latency where achieved using vectorisation and CPU cache considerations.
Instrumentation Radar analysis software
- Data visualisation of radar returns using OpenGL
- Multifunction I/O to interface A/D cards, optical trackers, weather stations, GPS clock, video titling and recording.
Making Tax Digital VAT Desktop App
- Author of the free 100PcVatFreeBridge Making Tax Digital for VAT desktop App.
- A free forever, HMRC recognised, multi-platform App written using JavaFx.
- Windows, MacOs or Linux to read Excel or CSV data files to make MTD VAT returns.
Timing system for 5k/10k fun runs
- Timing system for the local scouts to time the runners participating in a 5k/10k fun run.
- Runners are clicked in as they cross the line and results displayed on-line in real time.
Android Firework Display Synchronisation App
- Allows a firework display coordinator to synchronise and rate fireqorks in a display
DataLink Link 22 Algorithms
- Added Link22 capabilities (in C++) to an existing legacy DataLink Processor (in Ada).
- Responsibile for the particularly challenging areas of the Electronic Warfare Surveillance and implementing the Multi-Link specific requirements.
Infra Red model code review
- Reviewed a large Fortran Infra red model for estimating the radiance of objects in varying atmospheric scenarios and made a number of recommendations for code readability and performance improvements.
MXF Video Packaging Desktop App
- Created a tool using Java, RMI and JINI that allows users to manage the encoding / decoding and playback of MXF video files.
Laser Detector Proof of concept
- Remember Borland Turbo C++? This was used to interface two sensor arrays to create a pattern matching laser detector demonstrator running on MS-Dos.
HF Radio Signal Visualisation
- Enhanced several programs used in the calculation of radiation patterns from HF antennae using IRIX, Motif / X-Windows and OpenGL
3G UMTS Node B Test Harness
- Used UML and C++ to design and implement a generic, script driven test harness for sending ASN.1 encoded packets through the system
Terabit Network Router Simulator
- Modelled packet flow under various conditions for a 128 LIC Internet Router. Improved the throughput 6-fold and designed a novel unicast / multicast fair scheduling algorithm.
Nokia Phone Settings Transfer Box
- In the early days, before smartphones and Google backup etc. Copying your settings to a new phone was a daunting process. This transfer box, developed for Nokia, used RS-232 to copy settings from a host to a target phone.
This website 😄
I created this site using kobweb, an opinionated Kotlin framework for creating websites and web apps, built on top of Compose HTML.
Many thanks to UI Rocket for making the basic kobweb template freely available and to PhoenixRedwolf Digital Services for some of the layout ideas
Home