*/
+
+sdoc-toast {
+ pointer-events: initial;
+ text-align: center;
+ border-radius: var(--base-rhythm);
+ box-shadow: 0 8px 32px rgba(0,0,0,.3);
+ background: var(--color-bg-ui);
+ color: var(--color-fg-secondary-invert);
+}
+
+sdoc-toast:not(:empty) {
+ padding: .75rem 2rem;
+}
+
+sdoc-toast a,
+sdoc-toast a:link,
+sdoc-toast a:visited {
+ color: var(--color-bg-contrast);
+}
+
+sdoc-toast a:hover {
+ color: var(--color-fg-accent);
+}
diff --git a/tests/fuzz/20_L1_Open_Requirements_Tool_202511/assets/node.css b/tests/fuzz/20_L1_Open_Requirements_Tool_202511/assets/node.css
new file mode 100644
index 0000000..cf45ed3
--- /dev/null
+++ b/tests/fuzz/20_L1_Open_Requirements_Tool_202511/assets/node.css
@@ -0,0 +1,246 @@
+turbo-frame {
+ display: contents;
+}
+
+sdoc-node {
+ display: block;
+ position: relative;
+}
+
+/* sdoc-node[show-node-type-name] sdoc-node-content {
+ margin-top: calc(2 * var(--base-rhythm));
+} */
+
+sdoc-node[show-node-type-name]::before {
+ content: attr(show-node-type-name);
+ position: absolute;
+ top: calc(1 * var(--base-rhythm));
+ right: calc(4 * var(--base-rhythm));
+
+ font-size: 10px;
+ font-family: var(--code-font-family);
+ font-weight: 600;
+ line-height: 1;
+ text-transform: uppercase;
+
+ padding-top: calc(0.25 * var(--base-rhythm));
+ padding-bottom: calc(0.5 * var(--base-rhythm));
+ padding-left: calc(0.75 * var(--base-rhythm));
+ padding-right: calc(0.75 * var(--base-rhythm));
+ border-radius: 3px;
+ border: var(--requirement-border-width, 1px) solid var(--requirement-border-color, #bfbfbf);
+
+ color: var(--requirement-label-color);
+ background-color: var(--color-bg-contrast);
+}
+
+/* sdoc-node */
+
+sdoc-node {
+ background-color: var(--color-bg-contrast);
+ border-radius: 3px;
+
+ /* padding: calc(3 * var(--base-rhythm)) calc(4 * var(--base-rhythm)); */
+ padding-inline: calc(4 * var(--base-rhythm));
+ padding-block: calc(3 * var(--base-rhythm));
+}
+
+sdoc-node[node-role="root"] {
+ padding-top: calc(3 * var(--base-rhythm));
+}
+
+sdoc-node[node-style="readonly"][node-role="requirement"] {
+ background: none;
+ background-color: transparent;
+ outline: none;
+ padding-left: 0;
+ padding-right: 0;
+ padding-bottom: 0;
+ margin: 0;
+}
+
+sdoc-node[show-node-type-name][node-style="readonly"]::before {
+ right: 0;
+}
+
+sdoc-node[show-node-type-name][node-view="plain"]::before {
+ content: none;
+}
+
+/* editable_node */
+
+sdoc-node[node-style="card"][node-role="requirement"],
+[data-editable_node="on"] {
+ box-shadow: var(--base-elevation-0);
+ transition: box-shadow .5s;
+}
+
+sdoc-node[node-style="card"][node-role="requirement"]:hover,
+[data-editable_node="on"]:hover {
+ box-shadow: var(--base-elevation-node);
+ z-index: 10;
+}
+
+/* sdoc-node[node-style="card"] */
+
+sdoc-node[node-style="card"] {
+ background-color: var(--color-bg-contrast);
+ border-radius: 3px;
+ padding: 0;
+}
+
+sdoc-node[node-style="card"][node-role="text"],
+sdoc-node[node-style="card"][node-role="section"] {
+ background-color: var(--color-bg-contrast);
+ padding: calc(var(--base-rhythm)) calc(var(--base-rhythm)*2);
+}
+
+[data-role='current'] sdoc-node[node-style="card"] {
+ background-color: var(--color-bg-contrast);
+}
+
+[data-role='current'] [node-role="requirement"] {
+
+}
+
+[data-role='parents'] sdoc-node[node-style="card"],
+[data-role='children'] sdoc-node[node-style="card"] {
+ background-color: var(--color-bg-secondary);
+ width: var(--card-width);
+}
+
+sdoc-node[node-style="card"].highlighted {
+ background-color: var(--color-highlight);
+}
+
+[data-viewtype="traceability"] sdoc-node[node-style="card"] + sdoc-node[node-style="card"] {
+ margin-top: var(--base-padding);
+}
+
+[data-viewtype="deep_traceability"] sdoc-node[node-style="card"] {
+ /* width: var(--card-width); */
+ /* flex-grow: 1; */
+}
+
+[data-viewtype="requirements-coverage"] sdoc-node[node-style="card"] {
+ width: calc(var(--card-width)*0.75);
+ /* width: auto; */
+ font-size: .85em;
+ line-height: 1.4;
+}
+
+/* nouid */
+
+sdoc-node.nouid {
+ /* background-color: rgb(240, 220, 220); */
+}
+
+.nouid sdoc-node-title,
+.nouid .requirement__title {
+ color: #502222;
+}
+
+/* sdoc-node-controls */
+
+sdoc-node-controls[data-direction~="column"],
+sdoc-node-controls {
+ position: absolute;
+
+ display: flex;
+ justify-content: flex-start;
+
+ transition: .5s ease-out;
+ opacity: 0;
+
+ /* HACK: [sdoc-node outline hack] */
+ left: calc(100% + 1px);
+ top: -2px;
+
+ /* default: column to right */
+ bottom: 0;
+ right: unset;
+ width: calc(var(--base-rhythm)*4); /* determines the size of the buttons */
+ height: unset;
+
+ justify-content: flex-start;
+ flex-direction: column;
+}
+
+sdoc-node-controls[data-direction~="column"] {
+ flex-direction: column;
+ justify-content: flex-start;
+
+ left: 100%;
+ top: 0;
+ bottom: 0;
+ right: unset;
+ width: calc(var(--base-rhythm)*4); /* determines the size of the buttons */
+ height: unset;
+}
+
+sdoc-node-controls[data-direction~="row"] {
+ flex-direction: row;
+ justify-content: flex-end;
+
+ top: calc(100% - 4px);
+ left: 0;
+ right: 0;
+ bottom: unset;
+ height: calc(var(--base-rhythm)*4); /* determines the size of the buttons */
+ width: unset;
+}
+
+sdoc-main-placeholder + sdoc-node-controls {
+ opacity: 1;
+}
+
+sdoc-node-controls:hover,
+sdoc-node:hover sdoc-node-controls {
+ opacity: 1;
+}
+
+sdoc-node:hover sdoc-node-controls:hover {
+ opacity: 1;
+}
+
+sdoc-menu {
+ display: flex;
+ align-items: stretch;
+ /* default: */
+ flex-direction: column;
+}
+
+sdoc-menu-handler {
+ display: flex;
+ align-items: stretch;
+ /* default: */
+ flex-direction: column;
+}
+
+sdoc-menu, /* default: */
+sdoc-menu-handler, /* default: */
+sdoc-node-controls[data-direction~="column"] sdoc-menu,
+sdoc-node-controls[data-direction~="column"] sdoc-menu-handler {
+ flex-direction: column;
+}
+
+sdoc-node-controls[data-direction~="row"] sdoc-menu,
+sdoc-node-controls[data-direction~="row"] sdoc-menu-handler {
+ flex-direction: row;
+}
+
+/* math equation numbering support */
+div.math {
+ position: relative;
+ text-align: center;
+ padding-right: 3em; /* reserve space for eqno */
+ overflow: hidden; /* prevents scrollbars */
+}
+
+.math .eqno {
+ position: absolute;
+ right: 0;
+ top: 0;
+ font-size: 90%;
+ white-space: nowrap;
+}
\ No newline at end of file
diff --git a/tests/fuzz/20_L1_Open_Requirements_Tool_202511/assets/node_content.css b/tests/fuzz/20_L1_Open_Requirements_Tool_202511/assets/node_content.css
new file mode 100644
index 0000000..f1c4845
--- /dev/null
+++ b/tests/fuzz/20_L1_Open_Requirements_Tool_202511/assets/node_content.css
@@ -0,0 +1,495 @@
+:root {
+ --requirement-container-limit: 500px;
+ --requirement-border-color: rgb(230, 230, 230); /* = var(--color-border) on white without opacity */
+ --requirement-border-width: 1px;
+ --requirement-border-radius: 4px;
+ --requirement-inner-borders-width: 1px;
+ --requirement-label-color: var(--color-fg-secondary, #808080);
+ --requirement-bg-dark-color: var(--color-bg-main, #F2F5F9);
+ --requirement-bg-light-color: var(--color-bg-contrast, #FFFFFF);
+}
+
+/* sdoc-node-content */
+
+sdoc-node-content {
+ display: grid;
+ grid-template-columns: minmax(0, 1fr); /* issue#1370 https://css-tricks.com/preventing-a-grid-blowout/ */
+ place-items: stretch stretch;
+ place-content: stretch stretch;
+ gap: var(--requirement-inner-borders-width);
+
+ position: relative;
+ background-color: var(--color-bg-contrast); /* affects the color of the space between cells */
+ border:
+ var(--requirement-border-width, 1px)
+ solid
+ var(--requirement-border-color);
+
+ border-radius: var(--requirement-border-radius);
+
+
+ min-width: 300px;
+
+ /* and use overflow-wrap: break-word; in the field */
+ max-width: 100%;
+
+ /*
+ DEV: to show anchors (in the context) to the left of the node,
+ need to remove this:
+ overflow-x: auto;
+ */
+}
+
+/* Workaround for html2pdf4doc print bug:
+ (https://github.com/strictdoc-project/strictdoc/issues/2450#issuecomment-3299134769)
+ Disable background for elements that trigger header/footer overlap.
+ This hides the background of problematic split (not sliced) sections
+ to prevent them from covering header/footer areas during printing.
+ Real fix will be applied in html2pdf4doc in a future release. */
+@media print {
+ sdoc-node-content {
+ background: none;
+ background-color: transparent;
+ }
+}
+
+sdoc-node-title {
+ display: block;
+
+ font-size: 1.125em;
+ font-weight: 700;
+}
+
+sdoc-node-title:last-child {
+ margin-bottom: 0;
+}
+
+sdoc-node-title * {
+ /* affect H inside title, if applicable */
+ margin: 0;
+}
+
+[node-style="card"] sdoc-node-title {
+ font-size: 1em;
+}
+
+/* synonym to [node-view="inline"] */
+sdoc-node-content[node-view="simple"] sdoc-node-title {
+ padding-left: calc(var(--base-rhythm)*2);
+ padding-right: calc(var(--base-rhythm)*2);
+ padding-top: calc(var(--base-rhythm)*1);
+ padding-bottom: calc(var(--base-rhythm)*1);
+
+ word-break: break-word;
+ overflow-wrap: break-word;
+}
+
+/* sdoc-node-content[node-view="simple"] sdoc-node-title, */
+sdoc-node-content[node-view="table"] sdoc-node-title,
+sdoc-node-content[node-view="zebra"] sdoc-node-title {
+ padding-left: calc(var(--base-rhythm)*2);
+ padding-right: calc(var(--base-rhythm)*2);
+ padding-top: calc(var(--base-rhythm)*1);
+ padding-bottom: calc(var(--base-rhythm)*1);
+
+ border-top-right-radius: var(--requirement-border-radius);
+ border-top-left-radius: var(--requirement-border-radius);
+
+ background-color: var(--requirement-bg-dark-color);
+ /* border-bottom: */
+ outline: 1px solid var(--requirement-border-color);
+
+ word-break: break-word;
+ overflow-wrap: break-word;
+}
+
+sdoc-node-uid {
+ display: block;
+ padding-left: calc(var(--base-rhythm)*2);
+ padding-right: calc(var(--base-rhythm)*2);
+ padding-top: calc(var(--base-rhythm)*1);
+ padding-bottom: calc(var(--base-rhythm)*1);
+ font-size: var(--font-size-sm);
+ font-family: var(--code-font-family);
+ font-weight: 700;
+
+ text-transform: uppercase;
+ color: var(--requirement-label-color);
+
+ word-break: break-word;
+ overflow-wrap: break-word;
+}
+
+sdoc-node-field-label {
+ display: flex;
+ align-items:flex-start;
+
+ padding-left: calc(var(--base-rhythm)*2);
+ padding-right: calc(var(--base-rhythm)*2);
+ padding-top: calc(var(--base-rhythm)*1.75);
+ padding-bottom: calc(var(--base-rhythm)*1);
+
+ font-size: var(--font-size-sm);
+ font-family: var(--code-font-family);
+ font-weight: 500;
+ line-height: 1;
+ color: var(--requirement-label-color);
+
+ /* @mettta and @stanislaw are commenting this out because REQUIREMENT's field names
+ were split apart, even though there was enough screen width
+ word-break: break-word;
+ */
+ overflow-wrap: break-word;
+}
+
+sdoc-node-field {
+ display: block;
+ position: relative;
+
+ padding-left: calc(var(--base-rhythm)*2);
+ padding-right: calc(var(--base-rhythm)*2);
+ padding-top: calc(var(--base-rhythm)*1);
+ padding-bottom: calc(var(--base-rhythm)*1);
+
+ word-break: break-word;
+ overflow-wrap: break-word;
+}
+
+[data-viewtype="html2pdf"] sdoc-node-field-label {
+ word-break: normal;
+}
+
+/* for relations in requirement */
+sdoc-node-field > ol:first-child,
+sdoc-node-field > ul:first-child {
+ margin-top: 0;
+}
+sdoc-node-field > ol:last-child,
+sdoc-node-field > ul:last-child {
+ margin-bottom: 0;
+}
+
+/* node-view="plain" */
+
+sdoc-node-content[node-view="plain"] {
+ border: 0;
+ display: flex;
+ flex-direction: column;
+ gap: var(--base-padding);
+}
+
+sdoc-node-content[node-view="plain"] sdoc-node-field-label {
+ display: none;
+}
+
+sdoc-node-content[node-view="plain"] sdoc-node-field {
+ padding: 0;
+}
+
+/* node-view="table" */
+
+sdoc-node-content[node-view="table"] {
+ /* grid: */
+ grid-template-columns: minmax(80px, min-content) minmax(0, 1fr); /* issue#1370 https://css-tricks.com/preventing-a-grid-blowout/ */
+ /* border: */
+ background-color: var(--requirement-border-color);
+}
+
+sdoc-node-content[node-view="table"]
+ sdoc-node-title {
+ grid-column: 1 / 3;
+ }
+
+sdoc-node-content[node-view="table"]
+ sdoc-node-field-label {
+ grid-column: 1 / 2;
+ background-color: var(--requirement-bg-dark-color);
+ }
+
+sdoc-node-content[node-view="table"]
+ sdoc-node-field {
+ grid-column: 2 / 3;
+ background-color: var(--requirement-bg-light-color);
+ }
+
+sdoc-node:not([node-style="card"]) {
+ /* Making the node a container for the requirement: */
+ container: node / inline-size;
+ /*
+ HACK: [sdoc-node outline hack]
+ Buggy behavior for @container CSS feature:
+ after window resize, the 1px vertically space
+ appears randomly between nodes.
+ */
+ outline: 1px solid #fff;
+ margin: 1px 0;
+}
+
+/* calc(var(--card-width) + calc(var(--base-padding)*4)) */
+/* 300 + 16*4 = 364 */
+@container node (width < 400px) {
+ sdoc-node-content[node-view="table"] {
+ /* removes columns: */
+ grid-template-columns: minmax(0, 1fr); /* issue#1370 https://css-tricks.com/preventing-a-grid-blowout/ */
+ /* removes inner border: */
+ background-color: var(--requirement-bg-light-color);
+ }
+
+ sdoc-node-content[node-view="table"]
+ sdoc-node-title,
+ sdoc-node-content[node-view="table"]
+ sdoc-node-field-label,
+ sdoc-node-content[node-view="table"]
+ sdoc-node-field {
+ /* removes columns: */
+ grid-column: unset;
+ }
+}
+
+@supports not (container-type: inline-size) {
+ /* TODO test 888px */
+ @media (max-width: 888px) {
+ /* Do the same as if there was a container support */
+
+ sdoc-node-content[node-view="table"] {
+ /* removes columns: */
+ grid-template-columns: minmax(0, 1fr); /* issue#1370 https://css-tricks.com/preventing-a-grid-blowout/ */
+ /* removes inner border: */
+ background-color: var(--requirement-bg-light-color);
+ }
+
+ sdoc-node-content[node-view="table"]
+ sdoc-node-title,
+ sdoc-node-content[node-view="table"]
+ sdoc-node-field-label,
+ sdoc-node-content[node-view="table"]
+ sdoc-node-field {
+ /* removes columns: */
+ grid-column: unset;
+ }
+ }
+}
+
+/* node-view="zebra" */
+
+sdoc-node-content[node-view="zebra"] {
+ grid-template-columns: minmax(0, 1fr); /* issue#1370 https://css-tricks.com/preventing-a-grid-blowout/ */
+}
+
+sdoc-node-content[node-view="zebra"]
+ sdoc-node-field-label {
+ background-color: var(--requirement-bg-dark-color);
+ }
+
+sdoc-node-content[node-view="zebra"]
+ sdoc-node-field {
+ background-color: var(--requirement-bg-light-color);
+ }
+
+/* node-view="simple" */
+/* synonym to "inline" */
+
+sdoc-node-content[node-view="simple"] {
+ grid-template-columns: minmax(0, 1fr); /* issue#1370 https://css-tricks.com/preventing-a-grid-blowout/ */
+}
+
+sdoc-node-content[node-view="simple"]
+sdoc-node-field-label {
+ background-color: #fff;
+ padding-bottom: 0;
+}
+
+/* node-view="narrative" */
+
+sdoc-node-content[node-view="narrative"] {
+ display: flex;
+ flex-direction: column;
+ padding-top: var(--base-rhythm);
+ border-radius: 0;
+ border-left: none;
+ border-right: none;
+ border-bottom: none;
+}
+
+sdoc-node-content[node-view="narrative"] sdoc-node-title {
+ border: none;
+ outline: none;
+ background: none;
+ background-color: transparent;
+ padding: 0;
+ margin-bottom: var(--base-padding);
+ grid-column: 1 / -1;
+}
+
+sdoc-node-content[node-view="narrative"] sdoc-node-field {
+ padding: 0;
+}
+
+sdoc-node-content[node-view="narrative"] sdoc-node-field-label {
+ opacity: 0.8;
+ font-size: var(--font-size-sm);
+ line-height: calc(var(--font-size-sm) * 1.5);
+ padding: 0;
+}
+
+sdoc-node-content[node-view="narrative"] .node_fields_group-primary {
+ display: flex;
+ flex-direction: column;
+ padding-top: var(--base-padding);
+}
+
+sdoc-node-content[node-view="narrative"] .node_fields_group-primary sdoc-node-field {
+ margin-bottom: var(--base-padding);
+ color: var(--color-fg-contrast);
+}
+
+sdoc-node-content[node-view="narrative"] .node_fields_group-primary sdoc-node-field:last-child {
+ margin-bottom: 0;
+}
+
+sdoc-node-content[node-view="narrative"] .node_fields_group-secondary {
+ display: grid;
+ grid-template-columns: max-content 1fr;
+ gap: calc(.5 * var(--base-rhythm));
+}
+
+sdoc-node-content[node-view="narrative"] .node_fields_group-secondary sdoc-node-field {
+ font-size: var(--font-size-sm);
+ line-height: calc(var(--font-size-sm) * 1.5);
+ opacity: 0.6;
+}
+
+sdoc-node-content[node-view="narrative"] .requirement__parent-uid,
+sdoc-node-content[node-view="narrative"] .requirement__child-uid {
+ /*
+ affects UID in links;
+ make them lighter:
+ */
+ font-weight: normal;
+}
+
+/* section */
+
+sdoc-section,
+sdoc-section-title {
+ display: block;
+ margin: 0;
+}
+
+sdoc-section-title {
+ font-weight: 700;
+}
+
+sdoc-section-title {
+ margin-bottom: var(--base-padding);
+}
+
+sdoc-section-title:last-child {
+ margin-bottom: 0;
+}
+
+sdoc-section-title * {
+ margin: 0;
+
+ /* This rule, when the element starts the page when printed,
+ creates illegal margins,
+ which breaks the rhythm of HTML2PDF4DOC
+ and generates blank pages:
+ */
+ /* display: inline; */
+}
+
+/* TEXT node */
+
+sdoc-text,
+sdoc-section-text {
+ display: block;
+ margin: 0;
+}
+
+[node-style="card"] sdoc-text {
+ padding: var(--base-padding);
+}
+
+sdoc-section-text {
+ margin-top: var(--base-padding);
+}
+
+sdoc-section-text:first-child {
+ margin-top: 0;
+}
+
+/* meta */
+
+sdoc-meta {
+ display: grid;
+ grid-template-columns: minmax(min-content, max-content) minmax(min-content, 1fr);
+ place-items: stretch stretch;
+ place-content: stretch stretch;
+ position: relative;
+ border:
+ var(--requirement-border-width, 1px)
+ solid
+ var(--requirement-border-color);
+ border-radius: var(--requirement-border-radius);
+
+ font-size: var(--font-size-sm);
+ line-height: 24px; /* to keep the copy button from expanding out of the content line */
+ /* margin: var(--base-padding) 0; */
+ margin: 0;
+ padding: calc(var(--base-rhythm)*0.5);
+ row-gap: 2px;
+
+ width: fit-content;
+ max-width: 100%;
+ overflow-x: auto;
+}
+
+sdoc-meta-section,
+sdoc-meta-label,
+sdoc-meta-field {
+ display: flex;
+ align-items: flex-start;
+ padding: calc(var(--base-rhythm)*0.25) var(--base-rhythm);
+ background-color: var(--color-bg-contrast);
+}
+
+sdoc-meta-label {
+ grid-column: 1 / 2;
+ font-family: var(--code-font-family);
+ font-weight: 700;
+ text-transform: uppercase;
+ color: var(--requirement-label-color);
+ background-color: var(--color-bg-secondary);
+}
+
+sdoc-meta-field {
+ grid-column: 2 / 3;
+}
+
+sdoc-meta-section {
+ grid-column: 1 / -1;
+}
+
+/* PDF */
+/* There is no sdoc-node wrapper, so such neighbours and nesting is possible. */
+sdoc-text + sdoc-text,
+sdoc-text + sdoc-section,
+sdoc-text + sdoc-section-title,
+sdoc-section + sdoc-text,
+sdoc-section + sdoc-section,
+sdoc-section + sdoc-section sdoc-section-title {
+ margin-top: calc(var(--base-rhythm)*4);
+}
+
+/* requirement type tag */
+
+.requirement__type-tag {
+ /* font-size: var(--font-size-sm);
+ font-family: var(--code-font-family);
+ font-weight: 500;
+ line-height: 1;
+ text-transform: uppercase; */
+ color: var(--requirement-label-color);
+ white-space: nowrap;
+}
diff --git a/tests/fuzz/20_L1_Open_Requirements_Tool_202511/assets/pan_with_space.js b/tests/fuzz/20_L1_Open_Requirements_Tool_202511/assets/pan_with_space.js
new file mode 100644
index 0000000..2a04d2d
--- /dev/null
+++ b/tests/fuzz/20_L1_Open_Requirements_Tool_202511/assets/pan_with_space.js
@@ -0,0 +1,151 @@
+// This code in this file is a simplified version of the StackOverflow answer
+// taken from: https://stackoverflow.com/a/33948409/598057.
+
+const MOUSEMOVE_SPEED_FACTOR = 1;
+const KEYDOWN_SPEED_FACTOR = 20;
+const PWS_SELECTOR = "[js-pan_with_space]";
+
+function getPanElement() {
+ const element = document.querySelector(PWS_SELECTOR);
+ return element;
+}
+
+window.addEventListener('load', function () {
+ var state = {
+ spacePressed: false,
+ isDown: false,
+ startX: 0,
+ startY: 0
+ }
+
+ const element = getPanElement();
+ if (element) {
+ console.assert(!!element, "Expected a valid element.");
+
+ document.addEventListener("keydown", function (e) {
+ if (e.key === ' ' || e.key === 'Spacebar') {
+ // ' ' is standard, 'Spacebar' was used by IE9 and Firefox < 37
+
+ e.preventDefault();
+ e.stopPropagation();
+ state.spacePressed = true;
+ element.style.cursor = 'move';
+ element.style.scrollBehavior = 'auto';
+ return;
+ }
+
+ var moveFactor = KEYDOWN_SPEED_FACTOR;
+ if (e.altKey) {
+ moveFactor = KEYDOWN_SPEED_FACTOR * 10;
+ }
+
+ if (e.key === 'ArrowDown') {
+ e.preventDefault();
+ e.stopPropagation();
+ element.scrollTop = element.scrollTop + moveFactor;
+ }
+ else if (e.key === 'ArrowUp') {
+ e.preventDefault();
+ e.stopPropagation();
+ element.scrollTop = element.scrollTop - moveFactor;
+ }
+ else if (e.key === 'ArrowLeft') {
+ e.preventDefault();
+ e.stopPropagation();
+ element.scrollLeft = element.scrollLeft - moveFactor;
+ }
+ else if (e.key === 'ArrowRight') {
+ e.preventDefault();
+ e.stopPropagation();
+ element.scrollLeft = element.scrollLeft + moveFactor;
+ }
+ })
+
+ document.addEventListener("keyup", function (e) {
+ if (e.key === ' ' || e.key === 'Spacebar') {
+ // ' ' is standard, 'Spacebar' was used by IE9 and Firefox < 37
+ e.preventDefault();
+ e.stopPropagation();
+ state.spacePressed = false;
+ element.style.cursor = 'default';
+ element.style.scrollBehavior = '';
+ }
+ });
+
+ element.addEventListener("mousedown", function (e) {
+ if (!state.spacePressed) {
+ return;
+ }
+
+ // Tell the browser we're handling this event.
+ e.preventDefault();
+ e.stopPropagation();
+
+ // Calc the starting mouse X,Y for the drag.
+ state.startX = parseInt(e.clientX);
+ state.startY = parseInt(e.clientY);
+
+ var mouseX = parseInt(e.clientX);
+ var mouseY = parseInt(e.clientY);
+
+ state.isDown = true;
+ });
+
+ element.addEventListener("mouseup", function (e) {
+ if (!state.spacePressed) {
+ return;
+ }
+
+ e.preventDefault();
+ e.stopPropagation();
+
+ state.isDown = false;
+ });
+
+ element.addEventListener("mousemove", function (e) {
+ if (!state.isDown) {
+ return;
+ }
+
+ if (!state.spacePressed) {
+ return;
+ }
+
+ e.preventDefault();
+ e.stopPropagation();
+
+ var mouseX = parseInt(e.clientX);
+ var mouseY = parseInt(e.clientY);
+
+ var dx = mouseX - state.startX;
+ var dy = mouseY - state.startY;
+
+ state.startX = mouseX;
+ state.startY = mouseY;
+
+ var speedupFactor = MOUSEMOVE_SPEED_FACTOR;
+ element.scrollTo(
+ element.scrollLeft - dx * speedupFactor, element.scrollTop - dy * speedupFactor
+ );
+ });
+
+ element.addEventListener("mouseleave", function (e) {
+ // Tell the browser we're handling this event.
+ e.preventDefault();
+ e.stopPropagation();
+
+ state.isDown = false;
+ });
+ }
+});
+
+// When a window is loaded, scroll to the central column of the DTR tree.
+// The central column is the one where the current document's requirements are
+// listed top-to-bottom.
+document.addEventListener("DOMContentLoaded", function(event) {
+ const element = getPanElement();
+ if (element) {
+ const firstNode = element.querySelector('.content_item[data-role="current"]');
+ firstNode && firstNode.scrollIntoView({ behavior: 'smooth', block: 'nearest', inline: 'center' });
+ }
+});
diff --git a/tests/fuzz/20_L1_Open_Requirements_Tool_202511/assets/project_map.js b/tests/fuzz/20_L1_Open_Requirements_Tool_202511/assets/project_map.js
new file mode 100644
index 0000000..b6f8946
--- /dev/null
+++ b/tests/fuzz/20_L1_Open_Requirements_Tool_202511/assets/project_map.js
@@ -0,0 +1,1851 @@
+// map of the project for the stable_uri forwarder
+const projectMap = {
+ "strictdoc/docs/strictdoc_01_user_guide.html": [
+
+
+ {"MID":"c2d4542d5f1741c88dfcb4f68ad7dcbd","UID":"SDOC_UG","_LINK":"SDOC_UG" },
+
+ {"MID":"75a595ff028741d0bf9067bba8fb787a","_LINK":"1-Introduction" },
+
+ {"MID":"27023bf63c414fd998437961c77a0e2e","_LINK":"27023bf63c414fd998437961c77a0e2e" },
+
+ {"MID":"bcd0cf7c13cf4cf2ab176455aedc0c90","UID":"SDOC_UG_CONTACT","_LINK":"SDOC_UG_CONTACT" },
+
+ {"MID":"3ae6491057674be1abf057b7e0d9bf21","_LINK":"3ae6491057674be1abf057b7e0d9bf21" },
+
+ {"MID":"8e4ede8cdc70402b91a59026d31a7020","_LINK":"1.1.1-StrictDoc-office-hours" },
+
+ {"MID":"c46def916b6f4df692c95f47414feebb","_LINK":"c46def916b6f4df692c95f47414feebb" },
+
+ {"MID":"e0a00ca3085f444187050ce9576aa31b","_LINK":"2-Examples" },
+
+ {"MID":"2122186075e8455181178b01331101fa","UID":"SDOC_UG_HELLO_WORLD","_LINK":"SDOC_UG_HELLO_WORLD" },
+
+ {"MID":"ffbdb80fb21d48adbaeffb782d7994a2","_LINK":"ffbdb80fb21d48adbaeffb782d7994a2" },
+
+ {"MID":"83369fc77d584407b530b179a449479b","_LINK":"2.2-StrictDoc-Examples-repository" },
+
+ {"MID":"d6bde8e4055b42138d216b48692c8f26","_LINK":"d6bde8e4055b42138d216b48692c8f26" },
+
+ {"MID":"0a736f05ab154b2599988b63201d4f10","_LINK":"2.3-StrictDoc-Templates-repository" },
+
+ {"MID":"47c2088447d7452ba28962ee220ba63a","_LINK":"47c2088447d7452ba28962ee220ba63a" },
+
+ {"MID":"2b2e39c48cc740e5b8452d76881f667d","_LINK":"2.4-Other-examples" },
+
+ {"MID":"2eaa8bfe5a354fcbb704ea7fd94f3a0a","_LINK":"2eaa8bfe5a354fcbb704ea7fd94f3a0a" },
+
+ {"MID":"821b818006a14ed7aeb025d9ac8fe8b6","UID":"SDOC_UG_GETTING_STARTED","_LINK":"SDOC_UG_GETTING_STARTED" },
+
+ {"MID":"4e9f094a7b2949edb23c817c5e2276e4","_LINK":"3.1-Requirements" },
+
+ {"MID":"e7e4c2982d8e49deaa9b7413a09a4efa","_LINK":"e7e4c2982d8e49deaa9b7413a09a4efa" },
+
+ {"MID":"914da2bf10364a6fbd9fc7f48b96c6e5","_LINK":"3.2-Installing-StrictDoc-as-a-Pip-package-recommended-way" },
+
+ {"MID":"872a60c673854cfd909787f2379d88c7","_LINK":"872a60c673854cfd909787f2379d88c7" },
+
+ {"MID":"b3e2c50e2d7e46acbce7ea0c646776ca","_LINK":"3.3-Installing-nightly-StrictDoc-as-a-Pip-package" },
+
+ {"MID":"867f22a2767a434586d1ee4f7ee161fb","_LINK":"867f22a2767a434586d1ee4f7ee161fb" },
+
+ {"MID":"9e95ac9422f44aae92c0615176153815","_LINK":"3.4-Installing-StrictDoc-into-a-Docker-container" },
+
+ {"MID":"32e04944c2a14ead93248ff1ea37a68d","_LINK":"32e04944c2a14ead93248ff1ea37a68d" },
+
+ {"MID":"e441594df15841d38f717194b722f3de","_LINK":"3.5-Installing-StrictDoc-as-a-Snap-package-not-maintained" },
+
+ {"MID":"2adfe1bc6be542c3885ca4ea80b8d6e1","_LINK":"2adfe1bc6be542c3885ca4ea80b8d6e1" },
+
+ {"MID":"4af1193170a7416d81a799344dfc8ed6","_LINK":"3.6-Installing-StrictDoc-with-Nix" },
+
+ {"MID":"2045b5e37fc34a83b7457c43d816bf2c","_LINK":"2045b5e37fc34a83b7457c43d816bf2c" },
+
+ {"MID":"6cc72bf1a2a94999954e148a6bef374c","_LINK":"4-Running-StrictDoc" },
+
+ {"MID":"1685e4d63d9746b784b4a55f17b0de30","UID":"SECTION-UG-Static-HTML-export","_LINK":"SECTION-UG-Static-HTML-export" },
+
+ {"MID":"c092847abfa04295b63f943c951f24c8","_LINK":"c092847abfa04295b63f943c951f24c8" },
+
+ {"MID":"1a059d3ae7da45f8b53f3d74f3580980","UID":"SECTION-UG-Web-server","_LINK":"SECTION-UG-Web-server" },
+
+ {"MID":"1fc9f6f4f84d47439bf6aa3404227ca4","_LINK":"1fc9f6f4f84d47439bf6aa3404227ca4" },
+
+ {"MID":"9f7fcbdd8e564af8986349deb09745a5","_LINK":"4.3-Security-considerations" },
+
+ {"MID":"4fa89608f70e4a84a0e4b2930da28bbe","_LINK":"4fa89608f70e4a84a0e4b2930da28bbe" },
+
+ {"MID":"6d489d82b2e24bfeb2919be24262468f","UID":"SDOC_UG_IDE_SUPPORT","_LINK":"SDOC_UG_IDE_SUPPORT" },
+
+ {"MID":"aad57726976f4882982458de90d168c7","_LINK":"aad57726976f4882982458de90d168c7" },
+
+ {"MID":"24fb3436fa8c4b36929183eaac269376","UID":"SECTION-UG-SDoc-syntax","_LINK":"SECTION-UG-SDoc-syntax" },
+
+ {"MID":"556a4f61a4884f3088a743a0717f397f","_LINK":"556a4f61a4884f3088a743a0717f397f" },
+
+ {"MID":"43c9624d3c97433a97f8e8f39e2dd784","_LINK":"6.1-Document-structure" },
+
+ {"MID":"5419c0c9bfcc4922ac5aa79ddb333188","_LINK":"5419c0c9bfcc4922ac5aa79ddb333188" },
+
+ {"MID":"b4ceeb12bdf1448cb97b7974d4980189","UID":"SECTION-UG-DOCUMENT-ELEMENTS","_LINK":"SECTION-UG-DOCUMENT-ELEMENTS" },
+
+ {"MID":"db088d5977934056a851a24988e9266c","UID":"SECTION-UG-Document","_LINK":"SECTION-UG-Document" },
+
+ {"MID":"4b5c6f6fd70e44be8e5be10a38427e77","_LINK":"4b5c6f6fd70e44be8e5be10a38427e77" },
+
+ {"MID":"c75dc4ddd0c349e489817076877394a7","UID":"DOCUMENT_FIELD_OPTIONS","_LINK":"DOCUMENT_FIELD_OPTIONS" },
+
+ {"MID":"45f3cb9a3da54852a83670af72a4d21b","_LINK":"45f3cb9a3da54852a83670af72a4d21b" },
+
+ {"MID":"0f566e0d07bf4194adabc4fba2fdf919","_LINK":"6.2.1.1.1-ENABLE_MID" },
+
+ {"MID":"196b9e9d857548bebecc698903a593de","_LINK":"196b9e9d857548bebecc698903a593de" },
+
+ {"MID":"8cef59608d3942c88dc554f5531e2d8a","_LINK":"6.2.1.1.2-MARKUP" },
+
+ {"MID":"19f65eabcd1c4f28a0091133979b5b6e","_LINK":"19f65eabcd1c4f28a0091133979b5b6e" },
+
+ {"MID":"48c614864015426b8cb98d423201ad43","_LINK":"6.2.1.1.3-AUTO_LEVELS" },
+
+ {"MID":"915b35a9193348108e60968f9b60c1d0","_LINK":"915b35a9193348108e60968f9b60c1d0" },
+
+ {"MID":"8cde71c0f4d448c2a8939f9a81af7ac7","UID":"SECTION-UG-VIEW_STYLE","_LINK":"SECTION-UG-VIEW_STYLE" },
+
+ {"MID":"538a721c42824ad6b94a2f54780887ea","_LINK":"538a721c42824ad6b94a2f54780887ea" },
+
+ {"MID":"bdf01de0fc414b70a6a07118396b23b0","_LINK":"6.2.1.1.5-NODE_IN_TOC" },
+
+ {"MID":"e9e7522f3a094f5ea809f7bae93384d7","_LINK":"e9e7522f3a094f5ea809f7bae93384d7" },
+
+ {"MID":"726b6a1a2f854e82a7670cb8480b887e","_LINK":"6.2.1.2-Additional-Metadata" },
+
+ {"MID":"f86d45b7ad1a48ec919b43a695ca9126","_LINK":"f86d45b7ad1a48ec919b43a695ca9126" },
+
+ {"MID":"93085eee6a214a0a85aa94472f0a0a6c","UID":"SECTION-UG-Leaf-nodes","_LINK":"SECTION-UG-Leaf-nodes" },
+
+ {"MID":"23cbc84e92294aa0aeb0bb279d914480","_LINK":"6.2.2.1-TEXT" },
+
+ {"MID":"4474709783b74b1ca31fa754c712344e","_LINK":"4474709783b74b1ca31fa754c712344e" },
+
+ {"MID":"6426b56116ba428fbba395c79dc2eacc","_LINK":"6.2.2.2-REQUIREMENT" },
+
+ {"MID":"f221cd0c72f846b385ec2f0a9ddd15d5","_LINK":"f221cd0c72f846b385ec2f0a9ddd15d5" },
+
+ {"MID":"a1ad4861e5bc442baf38383b29c901a1","UID":"UG_COMPOSITE_NODE","_LINK":"UG_COMPOSITE_NODE" },
+
+ {"MID":"ce69fe89236a4bcfa104a640def4b64a","_LINK":"ce69fe89236a4bcfa104a640def4b64a" },
+
+ {"MID":"c8c15acf52a24c99922bdae6711f5120","UID":"ELEMENT_SECTION","_LINK":"ELEMENT_SECTION" },
+
+ {"MID":"14e5fea31b1c41bf8c743f18e51053e0","_LINK":"14e5fea31b1c41bf8c743f18e51053e0" },
+
+ {"MID":"9a571c9363ee4dc4a3cdc56abd2c57a7","_LINK":"6.2.3.1.1-Nesting-sections" },
+
+ {"MID":"fa700a9b975f493ba7ec2fd0a7b44bbe","_LINK":"fa700a9b975f493ba7ec2fd0a7b44bbe" },
+
+ {"MID":"0f52cfb294af480e806f0434d0a07757","_LINK":"6.2.3.1.2-Section-grammar-definition" },
+
+ {"MID":"7f2967ea1a41426ba15c0bdde2664920","_LINK":"7f2967ea1a41426ba15c0bdde2664920" },
+
+ {"MID":"324938c23b864864b4e8ff6a67b589a5","_LINK":"6.2.4-Reserved-fields" },
+
+ {"MID":"4d69fa95bd974d859973dbb34679a7c4","_LINK":"4d69fa95bd974d859973dbb34679a7c4" },
+
+ {"MID":"79b128720cd74a548d291e223b61c4bc","UID":"SECTION-UG-Machine-identifiers-MID","_LINK":"SECTION-UG-Machine-identifiers-MID" },
+
+ {"MID":"7fe2832d60014259a8d67a09f1db102a","_LINK":"7fe2832d60014259a8d67a09f1db102a" },
+
+ {"MID":"4afebe421fe341b8b609b1c24f47b708","_LINK":"6.2.4.1.1-Unique-vs-machine-identifiers-MID-vs-UID" },
+
+ {"MID":"a5a3d62d90f646aa8fac43795aa8fcbb","_LINK":"a5a3d62d90f646aa8fac43795aa8fcbb" },
+
+ {"MID":"6a7c6a10b0fc4db7a5b32abedc3bb31c","_LINK":"6.2.4.2-UID" },
+
+ {"MID":"2c3b050a2cd0444fb8948bb6adcb7085","_LINK":"2c3b050a2cd0444fb8948bb6adcb7085" },
+
+ {"MID":"f01eced244e842e28c0729d8458ac935","UID":"UG_NODE_WITHOUT_A_LEVEL","_LINK":"UG_NODE_WITHOUT_A_LEVEL" },
+
+ {"MID":"094425a33e8941d9a0016b4ed714c664","_LINK":"094425a33e8941d9a0016b4ed714c664" },
+
+ {"MID":"05c39a0bc4d9482ca4199c84b1981948","_LINK":"6.2.4.4-STATUS" },
+
+ {"MID":"448aa949724e4361a5b2f317c40c7492","_LINK":"6.2.4.5-TAGS" },
+
+ {"MID":"d7c2d72f849b413cb312d44813d25d5a","_LINK":"d7c2d72f849b413cb312d44813d25d5a" },
+
+ {"MID":"62480ac9dbdf4e4fb5c533abefa19997","_LINK":"6.2.4.6-TITLE" },
+
+ {"MID":"f5f9008f417e40aa8acd9da18ccd89d1","_LINK":"f5f9008f417e40aa8acd9da18ccd89d1" },
+
+ {"MID":"fb3b2d0bbf4c43abaa09b29b106346d4","_LINK":"6.2.4.7-STATEMENT" },
+
+ {"MID":"cea069906c2e4329bea0d97744984ba8","_LINK":"cea069906c2e4329bea0d97744984ba8" },
+
+ {"MID":"bf35d37584b34aabb5bf3b2e144beecb","_LINK":"6.2.4.8-RATIONALE" },
+
+ {"MID":"7e63bdbce418401da8eb5aa607fd8fc2","_LINK":"7e63bdbce418401da8eb5aa607fd8fc2" },
+
+ {"MID":"165b33aa61474a1db0ca0bd1f1279ba4","_LINK":"6.2.4.9-COMMENT" },
+
+ {"MID":"3928acde165b4505943154199ecd739a","_LINK":"3928acde165b4505943154199ecd739a" },
+
+ {"MID":"f10fd08172054423be7c00fcd16e61e9","UID":"SDOC_UG_REQUIREMENT_RELATIONS","_LINK":"SDOC_UG_REQUIREMENT_RELATIONS" },
+
+ {"MID":"c0c9c15d57e742ed80f12b8895f01de0","_LINK":"c0c9c15d57e742ed80f12b8895f01de0" },
+
+ {"MID":"c357b57be45a4871a6dfb877483de702","_LINK":"6.2.4.10.1-Relation-roles" },
+
+ {"MID":"a54f41576b2d40df92041862bef13600","_LINK":"a54f41576b2d40df92041862bef13600" },
+
+ {"MID":"57df0956302f4c728f6b35606320b660","UID":"UG_COMPOSABLE_DOCUMENTS","_LINK":"UG_COMPOSABLE_DOCUMENTS" },
+
+ {"MID":"6ed881a7cb8949cab3d1a1836846b716","_LINK":"6ed881a7cb8949cab3d1a1836846b716" },
+
+ {"MID":"952dd638d61c45ab950f271d53e56b2f","_LINK":"952dd638d61c45ab950f271d53e56b2f" },
+
+ {"MID":"0d29071c7f924ecdb11fc32da4ecc5e3","UID":"SECTION-UG-DOCUMENT-GRAMMAR","_LINK":"SECTION-UG-DOCUMENT-GRAMMAR" },
+
+ {"MID":"4c2244d6affb4653844f730e1de88266","_LINK":"4c2244d6affb4653844f730e1de88266" },
+
+ {"MID":"269600f411374fce975c3d7110ae74b6","_LINK":"6.3.1-Supported-field-types" },
+
+ {"MID":"a437c871dc3d46dba80460d5c8c22cf6","_LINK":"a437c871dc3d46dba80460d5c8c22cf6" },
+
+ {"MID":"3b9af7a4f6444664aa9e76343b477236","_LINK":"6.3.2-Grammar-element-properties" },
+
+ {"MID":"e1e5bda619f549188d8d7ae158aeaa44","_LINK":"6.3.2.1-IS_COMPOSITE" },
+
+ {"MID":"5396d4571b4c4204b093a44980a489ed","_LINK":"5396d4571b4c4204b093a44980a489ed" },
+
+ {"MID":"f2c8342dd6f5432c95ef6f80cf5e87ba","_LINK":"6.3.2.2-PREFIX" },
+
+ {"MID":"19d4dcbf0cd24f84996bcddb778e348c","_LINK":"19d4dcbf0cd24f84996bcddb778e348c" },
+
+ {"MID":"61df1b83c27e43909ad5640cf0d78962","UID":"SECTION-UG-VIEW_STYLE-2","_LINK":"SECTION-UG-VIEW_STYLE-2" },
+
+ {"MID":"4678706b4c864f459d1b478cd703fcc1","_LINK":"4678706b4c864f459d1b478cd703fcc1" },
+
+ {"MID":"04828fd96e2e42f3810af276d06859c1","UID":"SDOC_UG_GRAMMAR_RELATIONS","_LINK":"SDOC_UG_GRAMMAR_RELATIONS" },
+
+ {"MID":"012b0350547a48fc9ab3fbd6d9b5d502","_LINK":"012b0350547a48fc9ab3fbd6d9b5d502" },
+
+ {"MID":"16ce47f32874421986a5a843c5aeb2bf","UID":"SECTION-UG-Relation-roles","_LINK":"SECTION-UG-Relation-roles" },
+
+ {"MID":"01b8aa59963b42518d98c4e6b5e3259b","_LINK":"01b8aa59963b42518d98c4e6b5e3259b" },
+
+ {"MID":"ed4e4d30b3eb46ca976295aa27ede9e3","UID":"SDOC_UG_GRAMMAR_RELATIONS_PARENT_VS_CHILD","_LINK":"SDOC_UG_GRAMMAR_RELATIONS_PARENT_VS_CHILD" },
+
+ {"MID":"b119e614781044eab641e20eaec872e5","_LINK":"b119e614781044eab641e20eaec872e5" },
+
+ {"MID":"cd7d9c9b0efe443895d1b6eb44a3799b","_LINK":"6.3.4-IMPORT_FROM_FILE-Importing-grammar-from-file" },
+
+ {"MID":"df106206da0e446e87021fbf711fdb65","_LINK":"df106206da0e446e87021fbf711fdb65" },
+
+ {"MID":"d4292ad751ca407b8147e7204a934c4e","UID":"SDOC_UG_LINKS_AND_ANCHORS","_LINK":"SDOC_UG_LINKS_AND_ANCHORS" },
+
+ {"MID":"6ce1010a003146ec9e3e8d77ee89a082","_LINK":"6ce1010a003146ec9e3e8d77ee89a082" },
+
+ {"MID":"ac7ccc30e5bf489cb4929302c8ec21cf","_LINK":"6.4.1-Links" },
+
+ {"MID":"8b07c82f462348a58c3ab81be4db753d","_LINK":"8b07c82f462348a58c3ab81be4db753d" },
+
+ {"MID":"a1d9bb6b7df84b5eb6bf355542a5288a","_LINK":"6.4.2-Anchors" },
+
+ {"MID":"294d6a0e96424dc8a93d6502c43e8501","_LINK":"294d6a0e96424dc8a93d6502c43e8501" },
+
+ {"MID":"26b105a45eda470497148a7903ca731b","_LINK":"6.4.2.1-Anchor-example" },
+
+ {"MID":"ba71ef8f24b342178b28e87b7609b8d7","_LINK":"ba71ef8f24b342178b28e87b7609b8d7" },
+
+ {"MID":"ec9dcd4ad28a4852bc47723e667006df","_LINK":"6.5-Syntax-rules" },
+
+ {"MID":"926894ac8efc4e99943741691b3d4efe","UID":"SECTION-UG-Strict-rule-1","_LINK":"SECTION-UG-Strict-rule-1" },
+
+ {"MID":"2ebd1f2d3c8746a383d71232756c3bd3","_LINK":"2ebd1f2d3c8746a383d71232756c3bd3" },
+
+ {"MID":"1e465597f02842de92852be3a57f84cb","UID":"SECTION-UG-Strict-rule-2","_LINK":"SECTION-UG-Strict-rule-2" },
+
+ {"MID":"686eb01cf7db44c4bd1edd72ccb02ed0","_LINK":"686eb01cf7db44c4bd1edd72ccb02ed0" },
+
+ {"MID":"c741dd299b044fc9b72510256d48589e","UID":"SECTION-UG-Strict-rule-3","_LINK":"SECTION-UG-Strict-rule-3" },
+
+ {"MID":"c01ab5711463497498c91a968179d63c","_LINK":"c01ab5711463497498c91a968179d63c" },
+
+ {"MID":"31eb939aa5684f74b86be93ea7f14f7b","_LINK":"7-Markup" },
+
+ {"MID":"a3d675f38a1341548722239e994e55e1","_LINK":"a3d675f38a1341548722239e994e55e1" },
+
+ {"MID":"64d48546374e4bfd881733b0174fbebe","_LINK":"7.1-Images" },
+
+ {"MID":"e87ffdf6195c481cb39bc3d1ec29eca6","_LINK":"e87ffdf6195c481cb39bc3d1ec29eca6" },
+
+ {"MID":"83066d011cef4e8694aac5fbe90a357e","_LINK":"7.2-Mathjax-support" },
+
+ {"MID":"abdf406fe10847929dd7cb12a030456f","_LINK":"abdf406fe10847929dd7cb12a030456f" },
+
+ {"MID":"3e761d05262f44d29f48476c89ce3ca2","_LINK":"8-Export-formats" },
+
+ {"MID":"110260c57dbb47da87662686bc73d6e7","_LINK":"8.1-HTML-documentation-tree-by-StrictDoc" },
+
+ {"MID":"a6bfffddf89045a1a7ecf55c9681fe14","_LINK":"a6bfffddf89045a1a7ecf55c9681fe14" },
+
+ {"MID":"dcc6a2bc11424cf2b114b25a7f65530d","UID":"SECTION-UG-Inbound-Links","_LINK":"SECTION-UG-Inbound-Links" },
+
+ {"MID":"742831d32ca54791b53c1dbbbd070b55","_LINK":"742831d32ca54791b53c1dbbbd070b55" },
+
+ {"MID":"1b41e7c036cf4e3282fa3d4e687bf95d","_LINK":"8.1.2-Standalone-HTML-pages" },
+
+ {"MID":"5674bfd50f31420baf56625d79d1ebff","_LINK":"5674bfd50f31420baf56625d79d1ebff" },
+
+ {"MID":"f6091bab49714c1fa72c2fbca12c970b","UID":"SECTION-UG-HTML-export-via-Sphinx","_LINK":"SECTION-UG-HTML-export-via-Sphinx" },
+
+ {"MID":"bf8160f43703418db306785c48463123","_LINK":"bf8160f43703418db306785c48463123" },
+
+ {"MID":"c95a2b4c4fbd40fcbd92fe7f24c2cd91","UID":"SECTION-UG-PDF-export-via-Sphinx-LaTeX","_LINK":"SECTION-UG-PDF-export-via-Sphinx-LaTeX" },
+
+ {"MID":"58595abe6ff148afbb45e2b6adc25110","_LINK":"58595abe6ff148afbb45e2b6adc25110" },
+
+ {"MID":"e33a21323e2b48d692ed85cc56fd06e6","_LINK":"8.4-JSON" },
+
+ {"MID":"4d956edcd00846a98f59778dd7de9257","_LINK":"4d956edcd00846a98f59778dd7de9257" },
+
+ {"MID":"40050f96b9a64f57bbb0ad01f4d37264","_LINK":"9-Manage-project-tree" },
+
+ {"MID":"7f4b56d2a1104f539489bf7ddcdb1469","UID":"SECTION-UG-Automatic-assignment-of-requirements-UID","_LINK":"SECTION-UG-Automatic-assignment-of-requirements-UID" },
+
+ {"MID":"ed367ed0bc284d4d9318bf6c844c3e3e","_LINK":"ed367ed0bc284d4d9318bf6c844c3e3e" },
+
+ {"MID":"fa1cc31842144440a8ca310c7c0dedb2","UID":"SECTION-TRACEABILITY-REQS-TO-SOURCE-CODE","_LINK":"SECTION-TRACEABILITY-REQS-TO-SOURCE-CODE" },
+
+ {"MID":"4398b17f61ad4dd290e72d7888597f48","_LINK":"4398b17f61ad4dd290e72d7888597f48" },
+
+ {"MID":"845ff817ad9d483796b9dc6016bfc3c7","UID":"SECTION-UG-Language-aware-parsing-of-source-code","_LINK":"SECTION-UG-Language-aware-parsing-of-source-code" },
+
+ {"MID":"07bfe045a4934dd29d97fdb8ac567b7c","_LINK":"07bfe045a4934dd29d97fdb8ac567b7c" },
+
+ {"MID":"2cde4b7a4d42450c84c93989aeb4d53d","_LINK":"10.2-Linking-source-code-to-requirements" },
+
+ {"MID":"c787c538cc0a422fb2898b525ec1006d","_LINK":"c787c538cc0a422fb2898b525ec1006d" },
+
+ {"MID":"a72c5eceff5c446c968c0e23bda3d933","_LINK":"10.3-Linking-requirements-to-source-code" },
+
+ {"MID":"1c06fb7b90114633801d177459f482b5","_LINK":"1c06fb7b90114633801d177459f482b5" },
+
+ {"MID":"38599400293a4b31a7cb6cb748f3dfe5","UID":"SECTION-UG-File-relations-roles","_LINK":"SECTION-UG-File-relations-roles" },
+
+ {"MID":"4f477cb2e0ca42aaac814042f795b982","_LINK":"4f477cb2e0ca42aaac814042f795b982" },
+
+ {"MID":"c9da7df725564208971e7ee058ad8d73","UID":"SECTION-UG-Parsing-SDoc-source-nodes","_LINK":"SECTION-UG-Parsing-SDoc-source-nodes" },
+
+ {"MID":"72fe8c3f618042578850cfdf01868b6c","_LINK":"72fe8c3f618042578850cfdf01868b6c" },
+
+ {"MID":"31411ccbe80144868da8961ea2dd38bc","UID":"SECTION-UG-ReqIF-support","_LINK":"SECTION-UG-ReqIF-support" },
+
+ {"MID":"b510d9337e604bfda366f2ec605f4c88","_LINK":"b510d9337e604bfda366f2ec605f4c88" },
+
+ {"MID":"81f3e7ff2e584f789e0076d0ab560d45","_LINK":"11.1-Import-flow-ReqIF-SDoc" },
+
+ {"MID":"079ed6d7ec3f4040b59efce7ccd37267","_LINK":"079ed6d7ec3f4040b59efce7ccd37267" },
+
+ {"MID":"7d1678af20a84f5d8263061f36332773","_LINK":"11.2-Export-flow-SDoc-ReqIF" },
+
+ {"MID":"94641cac6b9748bfa2de8648ff197584","_LINK":"94641cac6b9748bfa2de8648ff197584" },
+
+ {"MID":"c87ecf181d564e44ad1981558bf2cab0","UID":"SECTION-UG-ReqIF-options","_LINK":"SECTION-UG-ReqIF-options" },
+
+ {"MID":"57dd1fb10ba64e2f8e0b75baf772b634","_LINK":"57dd1fb10ba64e2f8e0b75baf772b634" },
+
+ {"MID":"95643ee2edb84ad8b86f9cf2bb74aaae","UID":"SECTION-REQIF-DETAILS","_LINK":"SECTION-REQIF-DETAILS" },
+
+ {"MID":"edd5c3bf902e48deaee3248d12087a75","_LINK":"edd5c3bf902e48deaee3248d12087a75" },
+
+ {"MID":"5ad8e72bdcfb4ac1b942468af9180657","_LINK":"12-Excel-support" },
+
+ {"MID":"65c1657a8fb04179960fca4ece265b18","_LINK":"65c1657a8fb04179960fca4ece265b18" },
+
+ {"MID":"4a34ea5da82b4e469cf5a87178f69536","_LINK":"12.1-Import-flow-Excel-XLS-XLSX-SDoc" },
+
+ {"MID":"b01355b5a6d54409a0c7a684376a5278","_LINK":"b01355b5a6d54409a0c7a684376a5278" },
+
+ {"MID":"1cbdef9ee67b4392a3bdb64276e90e36","_LINK":"12.2-Export-flow-SDoc-Excel-XLSX" },
+
+ {"MID":"14161a9fa81d427f8a5a21367359339e","_LINK":"14161a9fa81d427f8a5a21367359339e" },
+
+ {"MID":"17a8adb92c8d4e7992e869355e73912d","_LINK":"13-Options" },
+
+ {"MID":"05f82bdf26f141738d2f511133633a2d","UID":"SDOC_UG_OPTIONS_PROJECT_LEVEL","_LINK":"SDOC_UG_OPTIONS_PROJECT_LEVEL" },
+
+ {"MID":"6449098df878484fbe8aed8a8b0e9a97","_LINK":"6449098df878484fbe8aed8a8b0e9a97" },
+
+ {"MID":"3671119d6a304d0b80c63f7e31faee88","_LINK":"13.1.1-Project-title" },
+
+ {"MID":"12501275599f4d7a954892e1a56778b9","_LINK":"12501275599f4d7a954892e1a56778b9" },
+
+ {"MID":"22741629bf054d6784faf541393e90d0","_LINK":"13.1.2-Path-to-assets" },
+
+ {"MID":"7d1102cda98c4ea18c6e646b73511097","_LINK":"7d1102cda98c4ea18c6e646b73511097" },
+
+ {"MID":"9fbabb0a6d0e46648f58ba7245776bd9","UID":"SECTION-UG-Path-to-cache-dir","_LINK":"SECTION-UG-Path-to-cache-dir" },
+
+ {"MID":"e94e9762cc0e4e1eafe57d0d9e03eb5b","_LINK":"e94e9762cc0e4e1eafe57d0d9e03eb5b" },
+
+ {"MID":"2c54380e174e42b6ba8eff74173ceb0f","_LINK":"13.1.4-Path-to-source-root" },
+
+ {"MID":"be42ecf5c8a84fc3bca0b73ea50647de","_LINK":"be42ecf5c8a84fc3bca0b73ea50647de" },
+
+ {"MID":"499fa0144cbd48c687ba0d5f9f7cb846","_LINK":"13.1.5-Path-to-custom-HTML2PDF-template" },
+
+ {"MID":"225dc4d22c084a67ae049fca1098bc1a","_LINK":"225dc4d22c084a67ae049fca1098bc1a" },
+
+ {"MID":"593a2abbdaa5470988103c70e87c4cfc","_LINK":"13.1.6-Include-exclude-document-paths" },
+
+ {"MID":"27e5981c451d4ad4938ab622e3cf0be2","_LINK":"27e5981c451d4ad4938ab622e3cf0be2" },
+
+ {"MID":"7284798d60a340c2a6369c651d1ee6be","_LINK":"13.1.7-Include-exclude-source-files-paths" },
+
+ {"MID":"3908f98fab5c47668ba752d0e93033ab","_LINK":"3908f98fab5c47668ba752d0e93033ab" },
+
+ {"MID":"b355fc6730d14eb1892ac6a25e47bf59","UID":"SDOC_UG_CONFIG_FEATURES","_LINK":"SDOC_UG_CONFIG_FEATURES" },
+
+ {"MID":"f43d8170c44b4d70ada2816fe71caf07","_LINK":"f43d8170c44b4d70ada2816fe71caf07" },
+
+ {"MID":"39f7752d17c848e4ae9acd53eaf8048b","_LINK":"13.1.8.1-Enable-all-features" },
+
+ {"MID":"d33880e1740d4d0892852cc8c425f66f","_LINK":"d33880e1740d4d0892852cc8c425f66f" },
+
+ {"MID":"35173b0d735a4d4f8c06256d1d4e1f89","_LINK":"13.1.8.2-Disable-all-features" },
+
+ {"MID":"9cf2ac683b7a4e939286146ef00631c1","_LINK":"9cf2ac683b7a4e939286146ef00631c1" },
+
+ {"MID":"fc0da01a4a114ddd888a90fd6a29e456","_LINK":"13.1.9-Server-configuration" },
+
+ {"MID":"c520cefdfe3e47ccb1a0ada95ee5c4f0","UID":"SECTION-UG-Host-and-port","_LINK":"SECTION-UG-Host-and-port" },
+
+ {"MID":"9943131c688c400b99e2db9ec4854480","_LINK":"9943131c688c400b99e2db9ec4854480" },
+
+ {"MID":"cc720b525adf46849f6117c18c97905e","_LINK":"13.2-Command-line-interface-options" },
+
+ {"MID":"d69f1fe42c754a34a5f360f47d4b4a5b","_LINK":"13.2.1-Project-title" },
+
+ {"MID":"81d8e1beb5904cb78dfde2712ff3f311","_LINK":"81d8e1beb5904cb78dfde2712ff3f311" },
+
+ {"MID":"6ea7b264c142461398e9c8711cfec8d3","_LINK":"13.2.2-Parallelization" },
+
+ {"MID":"f8ff07833ff942dfabdad2412350cd0c","_LINK":"f8ff07833ff942dfabdad2412350cd0c" },
+
+ {"MID":"8030a2ceb5014b9881529ef39d3c1fb7","_LINK":"14-Python-API" },
+
+ {"MID":"4504bffd6ced4aa78848ee9e03fdd4b7","_LINK":"4504bffd6ced4aa78848ee9e03fdd4b7" },
+
+ {"MID":"cb5115ac9a6d47a198ceac81c9d49b60","UID":"UG_PORTABILITY_CONSIDERATIONS","_LINK":"UG_PORTABILITY_CONSIDERATIONS" },
+
+ {"MID":"e15260727be84ce394386a4f95c627ae","_LINK":"e15260727be84ce394386a4f95c627ae" },
+
+ {"MID":"d49d64a25f654d0c9b39023e87e5fa19","_LINK":"16-Interoperability-with-other-tools" },
+
+ {"MID":"dc83f93c820944b6b04c0923a7ad7e69","UID":"SECTION-UG-Doxygen","_LINK":"SECTION-UG-Doxygen" },
+
+ {"MID":"a8664547ac7e41399d7d8d263869abc6","_LINK":"a8664547ac7e41399d7d8d263869abc6" },
+
+ {"MID":"1296f265cdd948d8a5c02fbfc1cc4065","_LINK":"16.2-Valispace" },
+
+ {"MID":"5fe39dedfa4640d2bd7127ff23b0e3de","_LINK":"5fe39dedfa4640d2bd7127ff23b0e3de" },
+
+ {"MID":"e3596b4fb0804ac28a8bb3d06bd81953","UID":"SDOC_UG_EXPERIMENTAL_FEATURES","_LINK":"SDOC_UG_EXPERIMENTAL_FEATURES" },
+
+ {"MID":"5b400736aec54789b2ed3ebcffcf961e","_LINK":"5b400736aec54789b2ed3ebcffcf961e" },
+
+ {"MID":"72fdb23051184714ab32e22859504a77","UID":"SECTION-UG-Search-and-filtering","_LINK":"SECTION-UG-Search-and-filtering" },
+
+ {"MID":"de584af947a445e5bcc782bab6a93baf","_LINK":"de584af947a445e5bcc782bab6a93baf" },
+
+ {"MID":"f2d766a310ef41959b0c6d581d042420","_LINK":"17.1.1-Query-engine" },
+
+ {"MID":"29ffc3e91d8045589b0837f647286128","_LINK":"29ffc3e91d8045589b0837f647286128" },
+
+ {"MID":"2da071ad45054d168a5ae2982266fb77","_LINK":"17.1.2-Filtering-content" },
+
+ {"MID":"d52d86750ad54ce1b3263ebb092451c0","_LINK":"d52d86750ad54ce1b3263ebb092451c0" },
+
+ {"MID":"241afbf6b7af40189eec8054d0d0201c","UID":"SECTION-UG-Project-statistics-screen","_LINK":"SECTION-UG-Project-statistics-screen" },
+
+ {"MID":"2fefc893de83432fa852886cc3a05fea","_LINK":"2fefc893de83432fa852886cc3a05fea" },
+
+ {"MID":"aa84a8c59a904c9dbb1052b1bff169bf","_LINK":"17.2.1-User-provided-custom-statistics-generator-experimental" },
+
+ {"MID":"7cf15de69efc46a5abe6b6fc786e4b71","_LINK":"7cf15de69efc46a5abe6b6fc786e4b71" },
+
+ {"MID":"aa7ebc36cd2947ac9aa293d6c76d8848","UID":"SECTION-UG-Diff-changelog-screen","_LINK":"SECTION-UG-Diff-changelog-screen" },
+
+ {"MID":"131a7392a33f4225a62539dd173a920b","_LINK":"131a7392a33f4225a62539dd173a920b" },
+
+ {"MID":"0a4573d025f14e61b84aad14349d42f4","UID":"SECTION-UG-HTML2PDF-document-generator","_LINK":"SECTION-UG-HTML2PDF-document-generator" },
+
+ {"MID":"6e610b9a381f4b5d9d26004dd286e001","_LINK":"6e610b9a381f4b5d9d26004dd286e001" },
+
+ {"MID":"61b3fa2fc31140ae95ae1a651cb18355","_LINK":"17.5-Mermaid-diagramming-and-charting-tool" },
+
+ {"MID":"6a4e4467a5c0451ea8291fd94309d525","_LINK":"6a4e4467a5c0451ea8291fd94309d525" },
+
+ {"MID":"74291dc6cfae47d2bae33066024f3807","_LINK":"17.6-Test-report-integration" },
+
+ {"MID":"07e78a4847554fbd87c44d7b11133f68","_LINK":"07e78a4847554fbd87c44d7b11133f68" },
+
+ {"MID":"e9c94abacb12425980aec8ed7ee752cb","_LINK":"17.6.1-JUnit-XML" },
+
+ {"MID":"eba63ebd45624139a8773cf42fe7d670","_LINK":"eba63ebd45624139a8773cf42fe7d670" },
+
+ {"MID":"06d9dbbeca204f5e8d0042e142b615bd","_LINK":"17.6.2-LLVM-Integrated-Tester-JUnit-XML-specifics" },
+
+ {"MID":"fab24f53f02f46e7a4cb49e333dfdc54","_LINK":"fab24f53f02f46e7a4cb49e333dfdc54" },
+
+ {"MID":"c7f5451905bf4fdb9a3a7dc97bb0e853","_LINK":"17.6.3-Robot-Framework-XML" },
+
+ {"MID":"6c3d98ca65cc40d585953237693ff2c6","_LINK":"6c3d98ca65cc40d585953237693ff2c6" },
+
+ {"MID":"66e608bfa6b8448598c0a732a27ddaad","_LINK":"17.7-Shadow-features" },
+
+ {"MID":"38fa0af0d01e479ba7f5be046bae02eb","_LINK":"38fa0af0d01e479ba7f5be046bae02eb" },
+
+ {"MID":"c3c6d6fe6e8140ca905d26dbbaae22b3","UID":"SDOC_UG_LIMIT","_LINK":"SDOC_UG_LIMIT" },
+
+ {"MID":"4fb2645146eb42c1be2152d480b61cfc","UID":"SDOC_UG_LIMIT_RST","_LINK":"SDOC_UG_LIMIT_RST" },
+
+ {"MID":"f7b039831f4e4c1ea19b45efe71c5365","_LINK":"f7b039831f4e4c1ea19b45efe71c5365" },
+
+ {"MID":"076c2ae8d627491a85ddcacc132a4bc5","UID":"SDOC_UG_LIMIT_WEB","_LINK":"SDOC_UG_LIMIT_WEB" },
+
+ {"MID":"911c454331634018b8de24186ae8e742","_LINK":"911c454331634018b8de24186ae8e742" },
+
+ {"MID":"2a49392c11d246ea8c69375764fc5362","_LINK":"18.2.1-Concurrent-use-of-web-user-interface" },
+
+ {"MID":"bdee3bde500a40878b70be44f113cf2c","_LINK":"bdee3bde500a40878b70be44f113cf2c" },
+
+ {"MID":"c5cfb2c7892f4137a3bc0c3136a55a89","_LINK":"19-Known-issues" },
+
+ {"MID":"9282f2d7218a4f2e967b6df45b0347ab","_LINK":"9282f2d7218a4f2e967b6df45b0347ab" },
+
+ {"MID":"7e4c91401d244149a1aa502d990f0052","UID":"SDOC_IMPL_2","_LINK":"SDOC_IMPL_2" },
+
+ {"MID":"ec83d51626ee4e0cbb75c500ee306b06","_LINK":"ec83d51626ee4e0cbb75c500ee306b06" },
+
+ {"MID":"b55c23b113d54802b5717f7a82a45bd2","_LINK":"20-Appendices" },
+
+ {"MID":"a72ae310493a42ba8ecdc7de2c42d4f2","UID":"SECTION-UG-FREETEXT-TEXT","_LINK":"SECTION-UG-FREETEXT-TEXT" },
+
+ {"MID":"2509cce7ee634c7a8878c5e1094b83f2","_LINK":"2509cce7ee634c7a8878c5e1094b83f2" },
+
+ {"MID":"bbe50de9a4d845a7aa91e32dd9335abe","_LINK":"20.1.1-How-to-migrate-from-FREETEXT-to-TEXT" },
+
+ {"MID":"5d2f033604824264b1cc05840997c6b8","_LINK":"5d2f033604824264b1cc05840997c6b8" },
+
+ {"MID":"2ed20461aeb4462b812432c08aa006be","UID":"SECTION-UG-NODE-MIGRATION","_LINK":"SECTION-UG-NODE-MIGRATION" },
+
+ {"MID":"9d55b69bf789487e814210da06fc4164","_LINK":"9d55b69bf789487e814210da06fc4164" },
+
+ {"MID":"6f15ef6876ba48598d5560aaf4664ec9","_LINK":"20.2.1-How-to-migrate-from-SECTION-to-SECTION" },
+
+ {"MID":"19fe5099aa034eddb960cc88953ace0e","_LINK":"19fe5099aa034eddb960cc88953ace0e" }, ],
+ "strictdoc/docs/strictdoc_02_feature_map.html": [
+
+
+ {"MID":"1696d73230f046d589d2d87dd29d48a9","UID":"SDOC_FEATURE_MAP","_LINK":"SDOC_FEATURE_MAP" },
+
+ {"MID":"f405431dc66e4d6786be020a62a4e5a3","_LINK":"f405431dc66e4d6786be020a62a4e5a3" },
+
+ {"MID":"01c07ca347a24181a92a5be6c8431094","UID":"SECTION-FM-SDoc-text-markup","_LINK":"SECTION-FM-SDoc-text-markup" },
+
+ {"MID":"dfd4d2d77c7247819e476f360ffff639","_LINK":"1.1-Definition" },
+
+ {"MID":"4c40803dd0f04af88fd722ba6b732270","UID":"SDOC-FEAT-1","_LINK":"SDOC-FEAT-1" },
+
+ {"MID":"3f422abd9abe4717a995ae4150df12e3","_LINK":"1.2-Use-case" },
+
+ {"MID":"8ea5b080819e47afa78bc346d671cf30","_LINK":"8ea5b080819e47afa78bc346d671cf30" },
+
+ {"MID":"fa7b37153def4eb4a6e9dcee079cba2a","_LINK":"1.3-Inspirations" },
+
+ {"MID":"104b6ff4623f4ac9a965aa789c4cf001","_LINK":"104b6ff4623f4ac9a965aa789c4cf001" },
+
+ {"MID":"87b1538be72a4ff7945b5bb95f856471","_LINK":"1.4-Screenshots" },
+
+ {"MID":"f48ae881c5134f77885202b019e124d4","_LINK":"f48ae881c5134f77885202b019e124d4" },
+
+ {"MID":"27bb9f0875d84d79bb882f6ca98ee1fa","_LINK":"2-HTML-export" },
+
+ {"MID":"4a0844b5938a488a89ac4b379fc7d956","_LINK":"2.1-Definition" },
+
+ {"MID":"8e6604c8b27b450cbd21c12dc8572291","UID":"SDOC-FEAT-2","_LINK":"SDOC-FEAT-2" },
+
+ {"MID":"4e46063e2031418298b55a1861179900","_LINK":"2.2-Screenshots" },
+
+ {"MID":"586f8745588b483b8e027021d90931ac","_LINK":"586f8745588b483b8e027021d90931ac" },
+
+ {"MID":"3ef4254efd8547a8adaf37e100f22724","_LINK":"3-Web-based-graphical-user-interface" },
+
+ {"MID":"bd3e1273cb244616956bddfc22c05638","_LINK":"3.1-Definition" },
+
+ {"MID":"2c1cde585d5944b5b7b5a0d5f72a98ed","UID":"SDOC-FEAT-3","_LINK":"SDOC-FEAT-3" },
+
+ {"MID":"6b5989db0e984c42b12440993c885987","_LINK":"3.2-Screenshots" },
+
+ {"MID":"28ce32fe182c45ce882b65c835620339","_LINK":"28ce32fe182c45ce882b65c835620339" },
+
+ {"MID":"5ac3e3c690494371bd9de04be5eae0b0","_LINK":"4-Traceability-between-requirements-and-source-code" },
+
+ {"MID":"538d26fae4644debbc8f244709b8be7b","_LINK":"4.1-Definition" },
+
+ {"MID":"e14eee106ea443e598378e55401914dc","UID":"SDOC-FEAT-4","_LINK":"SDOC-FEAT-4" },
+
+ {"MID":"ceec313d9ec040b9bcaaf64967ed6af8","_LINK":"4.2-Screenshots" },
+
+ {"MID":"363aae23cbb44f30aff42ef6a430ffdf","_LINK":"363aae23cbb44f30aff42ef6a430ffdf" },
+
+ {"MID":"a436d31c5f324eb0bb6b35f0a6ce598d","_LINK":"5-Document-grammar" },
+
+ {"MID":"f20223cddcb14e40b45f99045e2d3a3a","_LINK":"5.1-Definition" },
+
+ {"MID":"0bfcb6144dde487791d4f01164dd7e7c","UID":"SDOC-FEAT-5","_LINK":"SDOC-FEAT-5" },
+
+ {"MID":"f4763b00f9624cfd8b44f8e571f2aec6","_LINK":"5.2-Screenshots" },
+
+ {"MID":"3d3d3e2c1c974ed4a2382770225212d7","_LINK":"3d3d3e2c1c974ed4a2382770225212d7" },
+
+ {"MID":"5b511eac439c4e0a8aa2c60499be88d0","_LINK":"6-Composable-documents" },
+
+ {"MID":"ab4bc7b948154dbfbd4956d41cda8b75","_LINK":"6.1-Definition" },
+
+ {"MID":"e7b2d61545eb414f97345ecac25c52cc","UID":"SDOC-FEAT-6","_LINK":"SDOC-FEAT-6" },
+
+ {"MID":"dd4d9c0d593b46f8a0abfb3fd91356ae","_LINK":"7-Export-to-RST" },
+
+ {"MID":"ab0e4d27b6334b44bd4b46425842cdbe","_LINK":"7.1-Definition" },
+
+ {"MID":"dd686a557c3e4e50ba89538a74d39383","UID":"SDOC-FEAT-8","_LINK":"SDOC-FEAT-8" },
+
+ {"MID":"f0a7041347444f3a822129120faf0fcd","_LINK":"7.2-Screenshots" },
+
+ {"MID":"45be72764a73440b8abf313bb84420aa","_LINK":"45be72764a73440b8abf313bb84420aa" },
+
+ {"MID":"2e8e39a2198e4f8aa18a470a892e4d25","_LINK":"8-Export-to-PDF" },
+
+ {"MID":"381ebcd10ee241aaaa9fe3654870961c","_LINK":"8.1-Definition" },
+
+ {"MID":"5be4f35be2eb49faae7c33b5a2d83251","UID":"SDOC-FEAT-10","_LINK":"SDOC-FEAT-10" },
+
+ {"MID":"2d8b04efe57d4c0aa543ed974ace868e","_LINK":"8.2-Screenshots" },
+
+ {"MID":"15d6e791674c4c0ab54afb6a781f35c9","_LINK":"9-Query-engine-and-search-screen" },
+
+ {"MID":"91177d3444d9437e87032875ac8fcd7d","_LINK":"9.1-Definition" },
+
+ {"MID":"9c1e6cb601294891bcaae2b8c9042c59","UID":"SDOC-FEAT-7","_LINK":"SDOC-FEAT-7" },
+
+ {"MID":"631f1620053342c8a398a1a5d458f873","_LINK":"9.2-Screenshots" },
+
+ {"MID":"64afc2abdab847439c0c18420db7ba47","_LINK":"64afc2abdab847439c0c18420db7ba47" },
+
+ {"MID":"3475f60f31b5488aab981fd2b7b12d4c","_LINK":"10-Project-statistics" },
+
+ {"MID":"9bbcc02a46194852b9616ea4437ce976","_LINK":"10.1-Definition" },
+
+ {"MID":"2dd0b514a24f43a287a4096d0be0af58","UID":"SDOC-FEAT-11","_LINK":"SDOC-FEAT-11" },
+
+ {"MID":"7d215ba517fc4aee9dfb381279297cc7","_LINK":"10.2-Screenshots" },
+
+ {"MID":"bd5a4763e2ca4df497dbaeeff9ffbd71","_LINK":"bd5a4763e2ca4df497dbaeeff9ffbd71" },
+
+ {"MID":"0b3d7fad0ee643ef83617745c51e8e72","_LINK":"11-Documentation-diff-changelog" },
+
+ {"MID":"9cdf4d3af1014aea923f77b112e6b1e3","_LINK":"11.1-Definition" },
+
+ {"MID":"e9da42f8e39b438a8e8eada16b280706","UID":"SDOC-FEAT-12","_LINK":"SDOC-FEAT-12" },
+
+ {"MID":"c60c6fab5740469aa251bfa3a805f21f","_LINK":"11.2-Screenshots" },
+
+ {"MID":"1fad67b63724450bb63738cf7e29d051","_LINK":"1fad67b63724450bb63738cf7e29d051" },
+
+ {"MID":"f655f9a2bde044489233fa03d2891de1","_LINK":"12-ReqIF-support" },
+
+ {"MID":"1627a126e1184c5e9050206f2f1ab725","_LINK":"12.1-Definition" },
+
+ {"MID":"2845463f977d4b51ac788c2fc9cbd894","UID":"SDOC-FEAT-13","_LINK":"SDOC-FEAT-13" },
+
+ {"MID":"e1109c5b3b1c4068a0eace811684f0c0","_LINK":"13-Project-configuration" },
+
+ {"MID":"3c2a1a37e11c425184042d6dab3f050a","_LINK":"13.1-Definition" },
+
+ {"MID":"8fc72d79bfe940aba2cf041e263b92df","UID":"SDOC-FEAT-9","_LINK":"SDOC-FEAT-9" },
+
+ {"MID":"275658296e5342acab72102589096f15","_LINK":"13.2-Screenshots" },
+
+ {"MID":"100daefc4121415989324de1978d1f59","_LINK":"100daefc4121415989324de1978d1f59" }, ],
+ "strictdoc/docs/strictdoc_03_faq.html": [
+
+
+ {"MID":"a434bc71a7324efaaed7f5a58e56e544","UID":"SDOC_FAQ","_LINK":"SDOC_FAQ" },
+
+ {"MID":"5acdfccd5771492f95b70328bd599cf7","_LINK":"5acdfccd5771492f95b70328bd599cf7" },
+
+ {"MID":"e972c79015524961863e095280a81aab","_LINK":"1-What-is-StrictDoc" },
+
+ {"MID":"d8d92e4eb8254cbda8dcb37709a9df45","_LINK":"d8d92e4eb8254cbda8dcb37709a9df45" },
+
+ {"MID":"86827c92ec3a493d8a2382b75b5277a8","_LINK":"2-Resources-about-StrictDoc" },
+
+ {"MID":"f7083cf6a84e4b858b5e551f8c8a555a","_LINK":"2.1-Presentations" },
+
+ {"MID":"52342105083e4f80884959d4ca7f4dba","_LINK":"52342105083e4f80884959d4ca7f4dba" },
+
+ {"MID":"d22b63a405264a6a80d4ab3f9b2bf9c5","_LINK":"2.2-Blog-posts" },
+
+ {"MID":"b2f5aea77e504ee1b64a67be24bd3c58","_LINK":"b2f5aea77e504ee1b64a67be24bd3c58" },
+
+ {"MID":"d75bd4d35b4b425b90ec8667ffffe191","_LINK":"2.3-Screencasts-tutorials" },
+
+ {"MID":"9d23e77aa7f848cb8efca49f5cf41f77","_LINK":"9d23e77aa7f848cb8efca49f5cf41f77" },
+
+ {"MID":"74235945ec4a4116aecbc883ffba54b7","_LINK":"3-Which-web-server-is-recommended-for-StrictDoc-documentation" },
+
+ {"MID":"966a5c3babf84fc7a1454b2799d13470","_LINK":"966a5c3babf84fc7a1454b2799d13470" },
+
+ {"MID":"2e911dedb13348bf827f078bbbca44f4","_LINK":"4-Is-StrictDoc-compatible-with-Sphinx" },
+
+ {"MID":"ac35a712b4a84f4ab2b61feb15c1550d","_LINK":"ac35a712b4a84f4ab2b61feb15c1550d" },
+
+ {"MID":"235122d2c10748918c7c6ff736e39d18","UID":"SECTION-FAQ-How-did-the-SDoc-text-language-become-what-it-is","_LINK":"SECTION-FAQ-How-did-the-SDoc-text-language-become-what-it-is" },
+
+ {"MID":"b3561dd4f8e64f11a251c3471022aece","_LINK":"b3561dd4f8e64f11a251c3471022aece" },
+
+ {"MID":"1d4220cc9a5444a5bdbaee91c8c50670","_LINK":"6-How-StrictDoc-compares-to-other-tools" },
+
+ {"MID":"45093addf6ec4772a0289fd958ae61dc","_LINK":"45093addf6ec4772a0289fd958ae61dc" },
+
+ {"MID":"a4533ae81bfe446295242add9156198e","_LINK":"6.1-Doorstop" },
+
+ {"MID":"d0c305180d8747a1b70254eaf2c4f201","_LINK":"d0c305180d8747a1b70254eaf2c4f201" },
+
+ {"MID":"5012af516d18447caa3a2dbce97d3e4a","_LINK":"6.2-Sphinx" },
+
+ {"MID":"74b6be0dc2bb485987d8731348cdf5ce","_LINK":"74b6be0dc2bb485987d8731348cdf5ce" },
+
+ {"MID":"515bcae39d1f48eda0b72562871ab15a","_LINK":"6.3-Sphinx-Needs" },
+
+ {"MID":"602327a9b8654e1eab4bc265e172a63d","_LINK":"602327a9b8654e1eab4bc265e172a63d" },
+
+ {"MID":"4a77366154d74cf7ab34044bed1cd542","_LINK":"6.4-FRET" },
+
+ {"MID":"e3eb1be604c6499292339ecbe7620c60","_LINK":"e3eb1be604c6499292339ecbe7620c60" },
+
+ {"MID":"723731c256fc43dfb315a300f6429945","_LINK":"6.5-Other-tools" },
+
+ {"MID":"ad24dca8ed9c449ab76c1798f38eb37c","_LINK":"ad24dca8ed9c449ab76c1798f38eb37c" },
+
+ {"MID":"ff143a18e98144bd86e10e29616c187b","_LINK":"7-How-long-has-the-StrictDoc-project-been-around" },
+
+ {"MID":"47d60404cf574aebb8c83795589c4137","_LINK":"47d60404cf574aebb8c83795589c4137" },
+
+ {"MID":"6e5ed6bb36634220a0c583d21c96295f","_LINK":"8-Which-StrictDoc-statistics-are-available" },
+
+ {"MID":"730bfedff6b24c34a6d6331051fd76d3","_LINK":"730bfedff6b24c34a6d6331051fd76d3" }, ],
+ "strictdoc/docs/strictdoc_04_release_notes.html": [
+
+
+ {"MID":"4277890572a94f49bda9f32a80e43c06","_LINK":"None-Release-Notes" },
+
+ {"MID":"0dd2649ec4784c9480eac6f4aef3158b","_LINK":"0dd2649ec4784c9480eac6f4aef3158b" },
+
+ {"MID":"27d526d90cda48dfa5cbf17df88299ba","_LINK":"1-0-12-1-2025-09-18" },
+
+ {"MID":"7433a733b3794983b5e17169897c3732","_LINK":"7433a733b3794983b5e17169897c3732" },
+
+ {"MID":"f2a70deaf8164240951fca48510d7aa4","_LINK":"2-0-12-0-2025-09-17" },
+
+ {"MID":"a7e0cee58f054a50818f07a02bab7230","_LINK":"a7e0cee58f054a50818f07a02bab7230" },
+
+ {"MID":"721b576103a748c8a63d3147ec771b95","_LINK":"3-0-11-3-2025-09-07" },
+
+ {"MID":"e60129ab582946319616595111296e76","_LINK":"e60129ab582946319616595111296e76" },
+
+ {"MID":"4bd05b9073254db38322102f4bbc5096","_LINK":"4-0-11-2-2025-09-02" },
+
+ {"MID":"7776a30d522b4b5f9a6e405d20241566","_LINK":"7776a30d522b4b5f9a6e405d20241566" },
+
+ {"MID":"3e3043021e034cb69dfd9b62eecadbb3","_LINK":"5-0-11-1-2025-09-01" },
+
+ {"MID":"9a4bbed442b94d72859d70d31282efc1","_LINK":"9a4bbed442b94d72859d70d31282efc1" },
+
+ {"MID":"f53df5a2e9674373a8f52f1a01b5010d","_LINK":"6-0-11-0-2025-08-26" },
+
+ {"MID":"177963dca83748d89bfaeb01b3d663a8","_LINK":"177963dca83748d89bfaeb01b3d663a8" },
+
+ {"MID":"a5ab8dd5bc4045e99299eff729e430e6","_LINK":"7-0-10-1-2025-07-25" },
+
+ {"MID":"6d0bb97e7ef74fc1ae93cf2a91480e6a","_LINK":"6d0bb97e7ef74fc1ae93cf2a91480e6a" },
+
+ {"MID":"447ab1fa1d38453ab46e0002e6eb852d","_LINK":"8-0-10-0-2025-07-20" },
+
+ {"MID":"c536381cea6842f0b77c1aa5ac942ce0","_LINK":"c536381cea6842f0b77c1aa5ac942ce0" },
+
+ {"MID":"aa45a90bad3f4273ab46dade039ef4c6","_LINK":"9-0-9-4-2025-07-12" },
+
+ {"MID":"a25dd134646e462ca09e850481bccb2b","_LINK":"a25dd134646e462ca09e850481bccb2b" },
+
+ {"MID":"eca2ad204c8246a8b0f29a5eb8d7f799","_LINK":"10-0-9-3-2025-07-03" },
+
+ {"MID":"64706a3d4d9c4beda3597ffa9d92921a","_LINK":"64706a3d4d9c4beda3597ffa9d92921a" },
+
+ {"MID":"6665c867a01f49f59968ae83d2e928fe","_LINK":"11-0-9-2-2025-06-28" },
+
+ {"MID":"d56dfede85b84e07bd5ecddc82a576fc","_LINK":"d56dfede85b84e07bd5ecddc82a576fc" },
+
+ {"MID":"a5ab3ca7210f4c18a465e7686e71c15f","_LINK":"12-0-9-1-2025-06-14" },
+
+ {"MID":"fbf2c4dcf8154779b3ac914d9ff335c4","_LINK":"fbf2c4dcf8154779b3ac914d9ff335c4" },
+
+ {"MID":"71b0ec45b5644c5083085c83ef6be95e","_LINK":"13-0-9-0-2025-06-10" },
+
+ {"MID":"72d1a7e4b54d44e38778d87c74075dc8","_LINK":"72d1a7e4b54d44e38778d87c74075dc8" },
+
+ {"MID":"d64fb5003399496bbb18ffb6e05efaf4","_LINK":"14-0-8-0-2025-04-13" },
+
+ {"MID":"a7bd074d2dcd40a6af106e91720d90d3","_LINK":"a7bd074d2dcd40a6af106e91720d90d3" },
+
+ {"MID":"58b99c15df8445ce9832e24a17588e2c","_LINK":"15-0-7-0-2025-03-03" },
+
+ {"MID":"c5725f24fcd24d54929e155f6ad47b44","_LINK":"c5725f24fcd24d54929e155f6ad47b44" },
+
+ {"MID":"ff59e375101145b3bf12465ce2b5fc14","_LINK":"16-0-6-0-2025-02-16" },
+
+ {"MID":"3ddfc6462bec45b2ac69a1799293c7da","_LINK":"3ddfc6462bec45b2ac69a1799293c7da" },
+
+ {"MID":"d9e164994bb941ada8aecc73000bd51d","_LINK":"17-0-5-0-2025-01-06" },
+
+ {"MID":"d0d93f5eb37247079cc182e924dabd14","_LINK":"d0d93f5eb37247079cc182e924dabd14" },
+
+ {"MID":"e7df8274f42c4e01b02ad840e6b2569c","_LINK":"18-0-4-0-2024-12-25" },
+
+ {"MID":"f4e63483a11b442993c47b5d0574e89b","_LINK":"f4e63483a11b442993c47b5d0574e89b" },
+
+ {"MID":"591c1b85c6fb4453aee08e23cb9f257a","_LINK":"19-0-3-0-2024-11-21" },
+
+ {"MID":"b39a3b3d9f8640e380dad5a2fdb75d79","_LINK":"b39a3b3d9f8640e380dad5a2fdb75d79" },
+
+ {"MID":"f4cd860f07b1479ba1845bce3c749d68","_LINK":"20-0-2-1-2024-11-10" },
+
+ {"MID":"26043bba142a4e739dd206e229829202","_LINK":"26043bba142a4e739dd206e229829202" },
+
+ {"MID":"f76d863243b5410788e457b9c3bf1d2b","_LINK":"21-0-2-0-2024-11-04" },
+
+ {"MID":"611e8df13d464fd1b22e5026cf3ce531","_LINK":"611e8df13d464fd1b22e5026cf3ce531" },
+
+ {"MID":"83878b68483f4da2930bfb3712c08aa3","_LINK":"22-0-1-0-2024-11-01" },
+
+ {"MID":"e37e230c932448798bd9978d4f27f32c","_LINK":"e37e230c932448798bd9978d4f27f32c" },
+
+ {"MID":"771fb5350bf840e4b30485fe9e8d9452","_LINK":"23-0-0-60-2024-10-26" },
+
+ {"MID":"65daf4400b464021ba3cb7a06061e651","_LINK":"65daf4400b464021ba3cb7a06061e651" },
+
+ {"MID":"4538fe1994bc4730b7febe3dc624f704","_LINK":"24-0-0-59-2024-10-13" },
+
+ {"MID":"e9d5e3f8f6b04647afb95bae6b2f503a","_LINK":"e9d5e3f8f6b04647afb95bae6b2f503a" },
+
+ {"MID":"306a619f550f4be18db6dbb987df3248","_LINK":"25-0-0-58-2024-06-25" },
+
+ {"MID":"fd7f4d5b58e54f64aa43349684a675c4","_LINK":"fd7f4d5b58e54f64aa43349684a675c4" },
+
+ {"MID":"0795627e25e343f3b1b476b673a543ab","_LINK":"26-0-0-57-2024-06-23" },
+
+ {"MID":"f99185cb69cf47d4bc6e1bd404b67467","_LINK":"f99185cb69cf47d4bc6e1bd404b67467" },
+
+ {"MID":"cd994052a0354410a550858a1f25d426","_LINK":"27-0-0-56-2024-06-02" },
+
+ {"MID":"61f17be85ac442a0b70003825d671ced","_LINK":"61f17be85ac442a0b70003825d671ced" },
+
+ {"MID":"938f1a0fdcc94c5aaa87ddb18b880afe","_LINK":"28-0-0-55-2024-04-28" },
+
+ {"MID":"00abb07e55534a75a8cfd50d8cfc5732","_LINK":"00abb07e55534a75a8cfd50d8cfc5732" },
+
+ {"MID":"055ee004b28647629eead8165f198579","_LINK":"29-0-0-54-2024-04-17" },
+
+ {"MID":"e5bf489ac0684ea4b626574b5439c7dd","_LINK":"e5bf489ac0684ea4b626574b5439c7dd" },
+
+ {"MID":"87b7b54fa4024959bdcb42ded18f77f2","_LINK":"30-0-0-53-2024-04-01" },
+
+ {"MID":"2ac296f6326b4481beb7d67b95dbb23c","_LINK":"2ac296f6326b4481beb7d67b95dbb23c" },
+
+ {"MID":"36a70af62b3e4a5d8bf08d9345fda095","_LINK":"31-0-0-52-2024-03-25" },
+
+ {"MID":"72d6e38e89cc471b8d3f46ae5654e0e6","_LINK":"72d6e38e89cc471b8d3f46ae5654e0e6" },
+
+ {"MID":"6c72f8654ea1401ea2a6e4ab82cf76e4","_LINK":"32-0-0-51-2024-03-20" },
+
+ {"MID":"e81c4206bcb148979762ee3f2aa5c9ba","_LINK":"e81c4206bcb148979762ee3f2aa5c9ba" },
+
+ {"MID":"413952c14412434fb237c3e909101707","_LINK":"33-0-0-50-2024-03-19" },
+
+ {"MID":"a9d7c449d1a7400496504926c744e500","_LINK":"a9d7c449d1a7400496504926c744e500" },
+
+ {"MID":"3a03dd169ffb4fe0b64f48b365a77d2e","_LINK":"34-0-0-49-2024-03-11" },
+
+ {"MID":"0b8c8f40923744b089845afeb44223e9","_LINK":"0b8c8f40923744b089845afeb44223e9" },
+
+ {"MID":"a7ed1eaf155d4f588b27ba31ecc88d4d","_LINK":"35-0-0-48-2024-01-24" },
+
+ {"MID":"6cff333594d6430886053b59b265e806","_LINK":"6cff333594d6430886053b59b265e806" },
+
+ {"MID":"7a3620eecd1b4bd1a8eba7a373f14723","_LINK":"36-0-0-47-2023-11-20" },
+
+ {"MID":"c422af340d5b45c48bfe89130e1bba52","_LINK":"c422af340d5b45c48bfe89130e1bba52" }, ],
+ "strictdoc/docs/strictdoc_05_troubleshooting.html": [
+
+
+ {"MID":"5680165c90f44903b3b1dc1013b8cb59","UID":"SDOC_TROUBLESHOOTING","_LINK":"SDOC_TROUBLESHOOTING" },
+
+ {"MID":"7e3481d51ad14767b5c97132cad2e0a6","_LINK":"7e3481d51ad14767b5c97132cad2e0a6" },
+
+ {"MID":"17152ac7de9f4c138b85e2956091206f","_LINK":"1-Caching-issues" },
+
+ {"MID":"9a32ac13510d401cbc1a608259652c78","_LINK":"9a32ac13510d401cbc1a608259652c78" }, ],
+ "strictdoc/docs/strictdoc_10_contributing.html": [
+
+
+ {"MID":"1739e662499648d38c210a8aafbb3361","_LINK":"None-Contributing-to-StrictDoc" },
+
+ {"MID":"13fe652f160d4af69e869c28a155437d","_LINK":"13fe652f160d4af69e869c28a155437d" },
+
+ {"MID":"ec078ab0d7564738acd2961f72abb2c9","_LINK":"1-Contributor-checklist" },
+
+ {"MID":"ae0fc6d87b114137ab6da7c9b5647b62","_LINK":"ae0fc6d87b114137ab6da7c9b5647b62" },
+
+ {"MID":"8b40cc35f3524bc7b4e444321c080837","_LINK":"2-How-can-I-help" },
+
+ {"MID":"8e346888911649f2a3aaf49763aaef24","_LINK":"2.1-Spread-the-word" },
+
+ {"MID":"07462b02027a423a85ab68525b78ac67","_LINK":"07462b02027a423a85ab68525b78ac67" },
+
+ {"MID":"2696c7fda6d440f3a290f202bee08fe6","_LINK":"2.2-ReqIF-users" },
+
+ {"MID":"9cfbb025525f41c5a195be0e637dffee","_LINK":"9cfbb025525f41c5a195be0e637dffee" },
+
+ {"MID":"4e1edb97346c43af952c4e74f9defbe8","_LINK":"2.3-TeX-LaTeX-Sphinx-experts" },
+
+ {"MID":"75ed9362d86748269f62f5920514b7c2","_LINK":"75ed9362d86748269f62f5920514b7c2" }, ],
+ "strictdoc/docs/strictdoc_11_developer_guide.html": [
+
+
+ {"MID":"4f05169346ab4001b6ff19e8349e8fa7","_LINK":"None-Developer-Guide" },
+
+ {"MID":"f174b0cdec6b482daa2878c8cc0d02c3","_LINK":"f174b0cdec6b482daa2878c8cc0d02c3" },
+
+ {"MID":"c069e4c7b4d04dd09eb73f940e947bfd","UID":"DEVGUIDE_GETTING_STARTED","_LINK":"DEVGUIDE_GETTING_STARTED" },
+
+ {"MID":"7477d397d0ca493f8e47532455d44965","_LINK":"1.1-System-dependencies" },
+
+ {"MID":"df2e1de12c6b456898c48a36650813d4","_LINK":"df2e1de12c6b456898c48a36650813d4" },
+
+ {"MID":"b7a21564c30043acbf1733d9b47bd0bc","_LINK":"1.1.1-Windows-specific-Long-Path-support" },
+
+ {"MID":"8591cf6dece04244824c3ac2a8666ba3","_LINK":"8591cf6dece04244824c3ac2a8666ba3" },
+
+ {"MID":"89ec30b9f67c489da635be391b0b0e15","_LINK":"1.2-Installing-StrictDoc-from-GitHub-developer-mode" },
+
+ {"MID":"2407bb186b274a58b97b54b99ba6e86f","_LINK":"2407bb186b274a58b97b54b99ba6e86f" },
+
+ {"MID":"1814a8c25afc40cba6dca1696cae119b","_LINK":"1.2.1-Development-within-a-virtual-environment" },
+
+ {"MID":"a3e14b05452b48e2a0d8726fa00a7f00","_LINK":"a3e14b05452b48e2a0d8726fa00a7f00" },
+
+ {"MID":"90d5d79146e64660a71cd74ac23f6811","_LINK":"2-Invoke-for-development-tasks" },
+
+ {"MID":"452b3c24463446a497ed6b8fcdb31fef","_LINK":"452b3c24463446a497ed6b8fcdb31fef" },
+
+ {"MID":"e7ce6a2f13614974b43aba56f6ae7253","_LINK":"3-Main-Check-task" },
+
+ {"MID":"09258e99cabb4455904b0e2c6687d492","_LINK":"09258e99cabb4455904b0e2c6687d492" },
+
+ {"MID":"07d9a3c17be8475089844f5eb2cd8299","UID":"DEVGUIDE_PYTHON_CODE","_LINK":"DEVGUIDE_PYTHON_CODE" },
+
+ {"MID":"3012a69ef5d244d49fcb90c088d4523b","_LINK":"3012a69ef5d244d49fcb90c088d4523b" },
+
+ {"MID":"6e9707c99199464583f091056d1ae458","UID":"DEVGUIDE_GIT_WORKFLOW","_LINK":"DEVGUIDE_GIT_WORKFLOW" },
+
+ {"MID":"0e916453596b460b84a89f722354a825","_LINK":"0e916453596b460b84a89f722354a825" },
+
+ {"MID":"2420b2d7a4624bd99b0f8088dfa9abff","_LINK":"6-Frontend-development" },
+
+ {"MID":"d818aad87db54985b8933f98528808ab","_LINK":"d818aad87db54985b8933f98528808ab" },
+
+ {"MID":"73c717608cce4abca2c768f1dbfb705d","_LINK":"7-Running-End-to-End-Web-tests" },
+
+ {"MID":"da3cbcd69b0545988daeb0f42098830d","_LINK":"da3cbcd69b0545988daeb0f42098830d" },
+
+ {"MID":"240dc1426d994397ac1401834b4f0ef0","_LINK":"8-Running-integration-tests" },
+
+ {"MID":"4e307b3b950840bbbe455c1ae3238a6e","_LINK":"4e307b3b950840bbbe455c1ae3238a6e" },
+
+ {"MID":"7b4bf839b1c44b0d82001060596d8cbf","_LINK":"9-Documentation" },
+
+ {"MID":"d1f5fde86ebc4103bc4eb0334b1ec919","_LINK":"d1f5fde86ebc4103bc4eb0334b1ec919" },
+
+ {"MID":"a44e3b99323b4ac291f4b4d3948c3cc0","_LINK":"10-Conventions" },
+
+ {"MID":"49b7349a3bee478cbe81d8ef25f6245c","_LINK":"49b7349a3bee478cbe81d8ef25f6245c" }, ],
+ "strictdoc/docs/strictdoc_20_L1_Open_Requirements_Tool.html": [
+
+
+ {"MID":"b7bcca934cd148c3855beb4c85723bc5","_LINK":"None-Requirements-Tool-Specification-L1" },
+
+ {"MID":"c455f0297eb648c6aa9c6d239f043e0d","_LINK":"c455f0297eb648c6aa9c6d239f043e0d" },
+
+ {"MID":"668d18a7489043b38dd435933319e8e7","_LINK":"1-Summary-of-user-needs" },
+
+ {"MID":"7a94c3f55e32498187603400923bfae4","_LINK":"7a94c3f55e32498187603400923bfae4" },
+
+ {"MID":"1cbe275272994922a942fd088fa969d8","_LINK":"1.1-Free-and-open-source-tool" },
+
+ {"MID":"3ca29d12a7804f089f5b2aa955e4da59","_LINK":"3ca29d12a7804f089f5b2aa955e4da59" },
+
+ {"MID":"18136bcb9a5b4226a7a95d27dae49805","_LINK":"1.2-Document-types" },
+
+ {"MID":"14383453f84747d3abdce6b5dce50c7f","_LINK":"14383453f84747d3abdce6b5dce50c7f" },
+
+ {"MID":"973b586b8a89411ab4f083fd4c262cf5","UID":"SECTION-RTC-Appendix-A-Document-archetypes","_LINK":"SECTION-RTC-Appendix-A-Document-archetypes" },
+
+ {"MID":"4a847b9a58444e4a9be056db1f23272c","_LINK":"4a847b9a58444e4a9be056db1f23272c" },
+
+ {"MID":"52b6175f03d7495a9fa8dbffa36aeff4","UID":"SECTION-LRTS-Workflows","_LINK":"SECTION-LRTS-Workflows" },
+
+ {"MID":"c537b8fa5b54417eb9dff6478553f6d7","_LINK":"c537b8fa5b54417eb9dff6478553f6d7" },
+
+ {"MID":"08d547a3b04d485ca1f5a3a94a664ee1","_LINK":"1.4-Target-audience" },
+
+ {"MID":"847eaab505124e7797bd25c865f9d868","_LINK":"847eaab505124e7797bd25c865f9d868" },
+
+ {"MID":"f1ffdc7f78134d4b98f3c90e9be40cc7","UID":"SECTION-RTS-Documentation-management","_LINK":"SECTION-RTS-Documentation-management" },
+
+ {"MID":"0cacb010f5164118adce5dd8512c3e27","_LINK":"0cacb010f5164118adce5dd8512c3e27" },
+
+ {"MID":"72d0dd23dedd4907b4a8924debe7343b","UID":"SDOC-SSS-3","_LINK":"SDOC-SSS-3" },
+
+ {"MID":"9841bc9a56d740dd9e7988e52339618c","UID":"SDOC-SSS-91","_LINK":"SDOC-SSS-91" },
+
+ {"MID":"c4de5f1f46f343b6b4e8dc2a6121b0a2","UID":"SDOC-SSS-51","_LINK":"SDOC-SSS-51" },
+
+ {"MID":"5236f36f278140539e347bacea921118","UID":"SDOC-SSS-52","_LINK":"SDOC-SSS-52" },
+
+ {"MID":"8aeecdfa139341588d6ab8c0c3606a9b","UID":"SDOC-SSS-53","_LINK":"SDOC-SSS-53" },
+
+ {"MID":"d1883b65e17442c0a22987d4ad415cb6","UID":"SDOC-SSS-75","_LINK":"SDOC-SSS-75" },
+
+ {"MID":"b8d7b22fd8a6478a9a21ecaa60cf0028","UID":"SDOC-SSS-63","_LINK":"SDOC-SSS-63" },
+
+ {"MID":"3bb5252d75bc486b98e7606fb642bac0","UID":"SDOC-SSS-95","_LINK":"SDOC-SSS-95" },
+
+ {"MID":"fd227b9cfdc54d7db3134cdb925bde87","UID":"SECTION-RTS-Requirements-management","_LINK":"SECTION-RTS-Requirements-management" },
+
+ {"MID":"c1e2431cdf2141ca86931f29b9912ff7","_LINK":"c1e2431cdf2141ca86931f29b9912ff7" },
+
+ {"MID":"6e6f1464c47f4ced8e14c4153f40618b","UID":"SDOC-SSS-4","_LINK":"SDOC-SSS-4" },
+
+ {"MID":"db42ad4b504e48e0bf51b4d82529a888","UID":"SDOC-SSS-61","_LINK":"SDOC-SSS-61" },
+
+ {"MID":"a69bae43b3224dfc8439a88451a98395","UID":"SDOC-SSS-62","_LINK":"SDOC-SSS-62" },
+
+ {"MID":"5f89bdaa6cb74e2a8b9b030b6237b7ef","UID":"SDOC-SSS-64","_LINK":"SDOC-SSS-64" },
+
+ {"MID":"65575cc8a87e4d4480ccdf89d1fb6d67","UID":"SDOC-SSS-5","_LINK":"SDOC-SSS-5" },
+
+ {"MID":"06ab121d3c0f4d8c94652323b8f735c6","UID":"SDOC-SSS-70","_LINK":"SDOC-SSS-70" },
+
+ {"MID":"637c129a91804d8cbe2280c1af14836d","UID":"SDOC-SSS-6","_LINK":"SDOC-SSS-6" },
+
+ {"MID":"1ce495a5194044d4a7a3dd030f766c9f","UID":"SDOC-SSS-7","_LINK":"SDOC-SSS-7" },
+
+ {"MID":"44b9d75e50c84d6c8424cfb8a42a0771","UID":"SDOC-SSS-8","_LINK":"SDOC-SSS-8" },
+
+ {"MID":"387bd5ff0e4a4a97962661e9d7451f19","UID":"SDOC-SSS-71","_LINK":"SDOC-SSS-71" },
+
+ {"MID":"3348caaed8d44be0928cc6f3c7414094","UID":"SDOC-SSS-89","_LINK":"SDOC-SSS-89" },
+
+ {"MID":"3850f0b8c8294455bf7be9e2acddbd40","UID":"SDOC-SSS-47","_LINK":"SDOC-SSS-47" },
+
+ {"MID":"1216cb617c0f495a9c96471ef72bf80f","UID":"SDOC-SSS-57","_LINK":"SDOC-SSS-57" },
+
+ {"MID":"7c112f3a5885477084396fd26387a864","_LINK":"4-Tool-configurability" },
+
+ {"MID":"4550038552894ef69b85b281cff60c60","UID":"SDOC-SSS-92","_LINK":"SDOC-SSS-92" },
+
+ {"MID":"4550b38552894ef69b85b281cff60360","UID":"SDOC-SSS-93","_LINK":"SDOC-SSS-93" },
+
+ {"MID":"56dabce670be4691b35434bda6d6bb36","UID":"SECTION-SSSS-Performance","_LINK":"SECTION-SSSS-Performance" },
+
+ {"MID":"68e4b4b1ba78485f8620575ef9e1eaa2","_LINK":"68e4b4b1ba78485f8620575ef9e1eaa2" },
+
+ {"MID":"a0a95079e3c0438bb3ea9e5af7ddddc9","UID":"SDOC-SSS-13","_LINK":"SDOC-SSS-13" },
+
+ {"MID":"64b982c9299a4c8eb7031495e940a3f8","UID":"SDOC-SSS-14","_LINK":"SDOC-SSS-14" },
+
+ {"MID":"d1a483f3e321414b83bb4a39b1283293","_LINK":"6-Data-integrity" },
+
+ {"MID":"d1323d222a0040b2b6122c59b3c00f06","UID":"SDOC-SSS-94","_LINK":"SDOC-SSS-94" },
+
+ {"MID":"ec52fa5cc1714b07863eb7da9432be1d","UID":"SECTION-SSSS-Existing-workflows","_LINK":"SECTION-SSSS-Existing-workflows" },
+
+ {"MID":"33769a5f0ca94b99a4802adc81841037","_LINK":"33769a5f0ca94b99a4802adc81841037" },
+
+ {"MID":"831debedfa0e4e4c8434021569f96bad","UID":"SDOC-SSS-73","_LINK":"SDOC-SSS-73" },
+
+ {"MID":"5d412989005e4bc3b5dcfd94675615dc","UID":"SDOC-SSS-56","_LINK":"SDOC-SSS-56" },
+
+ {"MID":"5eb553abd3944bffbd003e37b3d1c5a5","UID":"SDOC-SSS-28","_LINK":"SDOC-SSS-28" },
+
+ {"MID":"06f0bb40f76142f4ba59d037aaedc9de","UID":"SDOC-SSS-48","_LINK":"SDOC-SSS-48" },
+
+ {"MID":"74ffae6279bc4e4095c03d6a247c3599","UID":"SDOC-SSS-29","_LINK":"SDOC-SSS-29" },
+
+ {"MID":"e0e6d1f883764719919238e4974dccef","UID":"SDOC-SSS-49","_LINK":"SDOC-SSS-49" },
+
+ {"MID":"ed4bd232bed84eda977263fa03e75b80","UID":"SDOC-SSS-74","_LINK":"SDOC-SSS-74" },
+
+ {"MID":"85d2f75b2f074f98ace5ceb5288c09b9","UID":"SECTION-RTC-Usability-installation-and-usage","_LINK":"SECTION-RTC-Usability-installation-and-usage" },
+
+ {"MID":"7e33387f373d427d9e1af522f1e5bbc5","UID":"SDOC-SSS-79","_LINK":"SDOC-SSS-79" },
+
+ {"MID":"57b01915e4624634909dbb40f5d56697","UID":"SDOC-SSS-80","_LINK":"SDOC-SSS-80" },
+
+ {"MID":"d3e66072363d4e7ea2e2f9691c094bb2","UID":"SDOC-SSS-81","_LINK":"SDOC-SSS-81" },
+
+ {"MID":"db495bc2f11f4f96ace60cdb0bef4d66","UID":"SDOC-SSS-82","_LINK":"SDOC-SSS-82" },
+
+ {"MID":"90562d92b9a7468ba42567bc72cb6ebf","UID":"SDOC-SSS-83","_LINK":"SDOC-SSS-83" },
+
+ {"MID":"4312ed066d19487eba18ec677430e60f","UID":"SDOC-SSS-84","_LINK":"SDOC-SSS-84" },
+
+ {"MID":"81858dda65844dcd9640fdd74badecee","UID":"SDOC-SSS-85","_LINK":"SDOC-SSS-85" },
+
+ {"MID":"ee96cc5f18e14f6894e2775c546240d8","UID":"SDOC-SSS-86","_LINK":"SDOC-SSS-86" },
+
+ {"MID":"f4b122c5081f4b218aa93a119e372a34","UID":"SDOC-SSS-87","_LINK":"SDOC-SSS-87" },
+
+ {"MID":"29fa83c59e714d0da8b36a9dc65b0c72","UID":"SECTION-SSSS-Implementation-suggestions","_LINK":"SECTION-SSSS-Implementation-suggestions" },
+
+ {"MID":"3db06eb066b4441290e06b08405da0a9","UID":"SDOC-SSS-30","_LINK":"SDOC-SSS-30" },
+
+ {"MID":"e718af582b0345c2b0ddb6e405cb6d9a","UID":"SDOC-SSS-31","_LINK":"SDOC-SSS-31" },
+
+ {"MID":"cd20e9613a65441a8862143ba6407f61","UID":"SDOC-SSS-32","_LINK":"SDOC-SSS-32" },
+
+ {"MID":"4475857729e5476cbbb409cc844048fd","UID":"SDOC-SSS-68","_LINK":"SDOC-SSS-68" },
+
+ {"MID":"5ac2f3010db84466bff854fc323e944c","UID":"SDOC-SSS-33","_LINK":"SDOC-SSS-33" },
+
+ {"MID":"b76fb774542849a182e2cdd89fdaab3c","UID":"SDOC-SSS-67","_LINK":"SDOC-SSS-67" },
+
+ {"MID":"871a7a66eb50436997fde692e90e93eb","UID":"SDOC-SSS-69","_LINK":"SDOC-SSS-69" },
+
+ {"MID":"0556a0b2773d4ee0b44b22773455a600","UID":"SDOC-SSS-90","_LINK":"SDOC-SSS-90" },
+
+ {"MID":"7bdea1a7cb9e4f6fbcf8497670f87278","UID":"SECTION-RTS-Text-based-requirements-language","_LINK":"SECTION-RTS-Text-based-requirements-language" },
+
+ {"MID":"dfe5a61ed10149bebcf69d9c5c3b1316","_LINK":"dfe5a61ed10149bebcf69d9c5c3b1316" },
+
+ {"MID":"f472e85f3398413795234a9298d4af3c","UID":"SDOC-SSS-88","_LINK":"SDOC-SSS-88" },
+
+ {"MID":"b13bc3dfa7324f238bc06a88baf5edb6","UID":"SDOC-SSS-55","_LINK":"SDOC-SSS-55" },
+
+ {"MID":"0b47da74f9ec45e6a77573185b95f327","UID":"SDOC-SSS-54","_LINK":"SDOC-SSS-54" },
+
+ {"MID":"13f3e7765b494237893c1585a7c9dfd0","UID":"SDOC-SSS-34","_LINK":"SDOC-SSS-34" },
+
+ {"MID":"8b1da9907bc847c989dc807b7dff2a05","UID":"SECTION-RTS-Requirements-and-source-code","_LINK":"SECTION-RTS-Requirements-and-source-code" },
+
+ {"MID":"4692362c77974fb8bcbeefdc248d0e89","UID":"SDOC-SSS-72","_LINK":"SDOC-SSS-72" },
+
+ {"MID":"cd9e353e07ae4d50b1aa08999854aa02","UID":"SECTION-RTS-Requirements-exchange-formats-export-import","_LINK":"SECTION-RTS-Requirements-exchange-formats-export-import" },
+
+ {"MID":"ecc76e0991e44d6282776365496193e6","_LINK":"ecc76e0991e44d6282776365496193e6" },
+
+ {"MID":"73e70548c2cf415f94adbf1066d5fe4b","UID":"SDOC-SSS-58","_LINK":"SDOC-SSS-58" },
+
+ {"MID":"c94de32c2c2e454d81c77724a4f29283","UID":"SDOC-SSS-59","_LINK":"SDOC-SSS-59" },
+
+ {"MID":"f7a600a238e34075ac6b65852492cc2f","UID":"SDOC-SSS-60","_LINK":"SDOC-SSS-60" },
+
+ {"MID":"efaa3e91045c4d49a70232f09a85ad35","UID":"SECTION-RTS-Requirements-collaboration","_LINK":"SECTION-RTS-Requirements-collaboration" },
+
+ {"MID":"f9d65df46ff24b0da6cb2bf011f0fc70","UID":"SDOC-SSS-65","_LINK":"SDOC-SSS-65" },
+
+ {"MID":"29d0374556494f38977ec3c928aa894d","UID":"SDOC-SSS-66","_LINK":"SDOC-SSS-66" },
+
+ {"MID":"f80a4b7ff03042849c3814c6cd5e5ca4","UID":"SECTION-SSSS-Development-process","_LINK":"SECTION-SSSS-Development-process" },
+
+ {"MID":"f16ea50f686e412f9c21d8096055bb47","UID":"SDOC-SSS-76","_LINK":"SDOC-SSS-76" },
+
+ {"MID":"0bebdf77108a499c87e5c0838204c39c","UID":"SDOC-SSS-50","_LINK":"SDOC-SSS-50" },
+
+ {"MID":"1a39a758930040029db320d8466806c1","UID":"SDOC-SSS-77","_LINK":"SDOC-SSS-77" },
+
+ {"MID":"8cb5ac6812924f4c8f4afd156b2f021c","UID":"SDOC-SSS-78","_LINK":"SDOC-SSS-78" },
+
+ {"MID":"e4cd429e9ec04deabfd1fb1381c39e38","UID":"SECTION-SSSS-Licensing-and-distribution","_LINK":"SECTION-SSSS-Licensing-and-distribution" },
+
+ {"MID":"92bf658bcddb4d2899b78c526fbddf38","_LINK":"92bf658bcddb4d2899b78c526fbddf38" },
+
+ {"MID":"2f30b94fdc074c8fa5858dfccc6202e8","UID":"SDOC-SSS-38","_LINK":"SDOC-SSS-38" },
+
+ {"MID":"27b640de8cae44a680b23429c981bee9","UID":"SDOC-SSS-39","_LINK":"SDOC-SSS-39" },
+
+ {"MID":"1338faad11204073a97212fa0fd11317","UID":"SDOC-SSS-40","_LINK":"SDOC-SSS-40" }, ],
+ "strictdoc/docs/strictdoc_21_L2_StrictDoc_Requirements.html": [
+
+
+ {"MID":"8a87daf19a7c487f89f396406a974509","_LINK":"None-StrictDoc-Requirements-Specification-L2" },
+
+ {"MID":"bd8a7931c1e04df9bf08d291488c67aa","_LINK":"1-SDoc-data-model" },
+
+ {"MID":"e8d5b55055254144b96d1ffeb587ec72","UID":"SDOC-SRS-18","_LINK":"SDOC-SRS-18" },
+
+ {"MID":"3b31cad22529476db01aca41caf39750","UID":"SDOC-SRS-26","_LINK":"SDOC-SRS-26" },
+
+ {"MID":"8e2ffffd33af4a969d5bb7ca40cb49a4","UID":"SDOC-SRS-100","_LINK":"SDOC-SRS-100" },
+
+ {"MID":"2d4020ba06d74571aef7aafe8604215b","UID":"SDOC-SRS-132","_LINK":"SDOC-SRS-132" },
+
+ {"MID":"f94419a390f2403daa3c4cd0e96f6cb6","UID":"SDOC-SRS-98","_LINK":"SDOC-SRS-98" },
+
+ {"MID":"435f856197d743c1b9b1dcbe91a22863","UID":"SDOC-SRS-110","_LINK":"SDOC-SRS-110" },
+
+ {"MID":"abcced8724d743c1b9b1dcbe91a22863","UID":"SDOC-SRS-151","_LINK":"SDOC-SRS-151" },
+
+ {"MID":"63821c507d584cf985f05904710b9779","UID":"SDOC-SRS-99","_LINK":"SDOC-SRS-99" },
+
+ {"MID":"899d2f68749b4be1a3124fe4d01de1aa","UID":"SDOC-SRS-135","_LINK":"SDOC-SRS-135" },
+
+ {"MID":"983653fc26214f46977dc792d65ae65f","UID":"SDOC-SRS-109","_LINK":"SDOC-SRS-109" },
+
+ {"MID":"fad4cf5dcf4d40518c7c9826fd6bd18a","UID":"SDOC-SRS-31","_LINK":"SDOC-SRS-31" },
+
+ {"MID":"9930894b08c44f5eba996c0a255e9e3f","UID":"SDOC-SRS-101","_LINK":"SDOC-SRS-101" },
+
+ {"MID":"fa090bc6976c4275aadbf522da6b920b","UID":"SDOC-SRS-149","_LINK":"SDOC-SRS-149" },
+
+ {"MID":"54132bc6976c4275aadbf522da6b920b","UID":"SDOC-SRS-150","_LINK":"SDOC-SRS-150" },
+
+ {"MID":"cbc7f72c6e0b4c858817bf17357105a5","_LINK":"2-SDoc-text-markup" },
+
+ {"MID":"27a6da48c65445539e536ee034921fb5","UID":"SDOC-SRS-20","_LINK":"SDOC-SRS-20" },
+
+ {"MID":"1f147feed60245378de2e099facd196d","UID":"SDOC-SRS-136","_LINK":"SDOC-SRS-136" },
+
+ {"MID":"f48a57c0cd764951a667127ce92fdb12","UID":"SDOC-SRS-127","_LINK":"SDOC-SRS-127" },
+
+ {"MID":"9df34a7ab79842d99ee68303f334d4eb","UID":"SDOC-SRS-104","_LINK":"SDOC-SRS-104" },
+
+ {"MID":"8dd6dd3979484dadbe71ac91aab50608","UID":"SDOC-SRS-105","_LINK":"SDOC-SRS-105" },
+
+ {"MID":"e5e3033c13f24fa083423230da7994f7","UID":"SDOC-SRS-19","_LINK":"SDOC-SRS-19" },
+
+ {"MID":"b97418ceccff438cb0457ed4bdf1be47","UID":"SDOC-SRS-93","_LINK":"SDOC-SRS-93" },
+
+ {"MID":"8924c29136944f65ac5efc8b6b90a07b","UID":"SDOC-SRS-21","_LINK":"SDOC-SRS-21" },
+
+ {"MID":"10d23bfbf4504c2e8c995ae89c500be4","UID":"SDOC-SRS-122","_LINK":"SDOC-SRS-122" },
+
+ {"MID":"5405c74a9eba4e9193007f01ea98bc85","UID":"SDOC-SRS-22","_LINK":"SDOC-SRS-22" },
+
+ {"MID":"f871dfc381354daf820cc1e2b94fdb05","UID":"SDOC-SRS-24","_LINK":"SDOC-SRS-24" },
+
+ {"MID":"b1b4f03d4e404a14be481626803fcfc2","UID":"SDOC-SRS-27","_LINK":"SDOC-SRS-27" },
+
+ {"MID":"39f117b79cfa4a8485c458280b3d36ce","UID":"SDOC-SRS-23","_LINK":"SDOC-SRS-23" },
+
+ {"MID":"98628e1db3ca4f52b7632674b69dd657","UID":"SDOC-SRS-25","_LINK":"SDOC-SRS-25" },
+
+ {"MID":"34b4abc6bb4649de9e56af31c229b0d1","UID":"SECTION-SRS-Graph-database","_LINK":"SECTION-SRS-Graph-database" },
+
+ {"MID":"2c8d7940a23c443f81a7eb373340894e","UID":"SDOC-SRS-28","_LINK":"SDOC-SRS-28" },
+
+ {"MID":"272b8933276d4cd48a78fcfa11899573","UID":"SDOC-SRS-29","_LINK":"SDOC-SRS-29" },
+
+ {"MID":"8330d61fd5b1438fa90f127f88903a0d","UID":"SDOC-SRS-30","_LINK":"SDOC-SRS-30" },
+
+ {"MID":"07a1e7bef11d4fcca86cd31ee5245d8d","UID":"SDOC-SRS-32","_LINK":"SDOC-SRS-32" },
+
+ {"MID":"2dad5f293bc442eaa98859c4b5eac0d5","UID":"SDOC-SRS-102","_LINK":"SDOC-SRS-102" },
+
+ {"MID":"4dce611287954289b1c2a6a15c413611","_LINK":"4-Documentation-tree" },
+
+ {"MID":"50b2d5d6eb1140f0a2b980203468a5f7","UID":"SDOC-SRS-115","_LINK":"SDOC-SRS-115" },
+
+ {"MID":"fcbf717009ce4cb2a8def7eb7b377654","UID":"SECTION-SRS-Web-HTML-frontend","_LINK":"SECTION-SRS-Web-HTML-frontend" },
+
+ {"MID":"a3603184d571449792f5cd752c978686","UID":"SECTION-SRS-General-export-requirements-2","_LINK":"SECTION-SRS-General-export-requirements-2" },
+
+ {"MID":"37f17fdd57ff47e9b7f4147adaeabde1","UID":"SDOC-SRS-49","_LINK":"SDOC-SRS-49" },
+
+ {"MID":"37399be2a8ac46889e3437209f9dffa9","UID":"SDOC-SRS-50","_LINK":"SDOC-SRS-50" },
+
+ {"MID":"f2fd90ad8a2946e7b085233a9c7a8a75","UID":"SDOC-SRS-51","_LINK":"SDOC-SRS-51" },
+
+ {"MID":"8811f0ef33de4365bc66a602a8c184f6","UID":"SDOC-SRS-48","_LINK":"SDOC-SRS-48" },
+
+ {"MID":"b99ebebdadb94fec968785429cef9002","UID":"SECTION-SRS-Screen-Project-tree","_LINK":"SECTION-SRS-Screen-Project-tree" },
+
+ {"MID":"100fa410f4b443e69c48738899cfb5bd","UID":"SDOC-SRS-53","_LINK":"SDOC-SRS-53" },
+
+ {"MID":"eb04abcfd64146f3b7be509afd1693f9","UID":"SDOC-SRS-107","_LINK":"SDOC-SRS-107" },
+
+ {"MID":"de7cda1156e043d7999933a2df630a30","UID":"SDOC-SRS-108","_LINK":"SDOC-SRS-108" },
+
+ {"MID":"185cfc2d1ed4429ebaf0689f70a8cb0a","UID":"SECTION-SRS-Screen-Document-DOC","_LINK":"SECTION-SRS-Screen-Document-DOC" },
+
+ {"MID":"9c962637ef7f45b6af6c83964b0a06d9","UID":"SDOC-SRS-54","_LINK":"SDOC-SRS-54" },
+
+ {"MID":"201187122be14ea48d69106d396c6790","UID":"SDOC-SRS-106","_LINK":"SDOC-SRS-106" },
+
+ {"MID":"13968ae160744e10ba8979eaee2f4f54","UID":"SDOC-SRS-55","_LINK":"SDOC-SRS-55" },
+
+ {"MID":"edc02a3a97704007b70b93102c76b278","UID":"SDOC-SRS-92","_LINK":"SDOC-SRS-92" },
+
+ {"MID":"197e00dd3b1d42309250c89de23ea51b","UID":"SDOC-SRS-56","_LINK":"SDOC-SRS-56" },
+
+ {"MID":"2706ac7ccb8148edb7b200a1b78c25d6","UID":"SDOC-SRS-57","_LINK":"SDOC-SRS-57" },
+
+ {"MID":"d64f7a0f6ba54672a62634304c54e2d4","UID":"SDOC-SRS-96","_LINK":"SDOC-SRS-96" },
+
+ {"MID":"956371b6a7824d0b91caa5603faeeae2","UID":"SDOC-SRS-120","_LINK":"SDOC-SRS-120" },
+
+ {"MID":"738b63b7f55b43eb99f5600bd65f5ba7","UID":"SDOC-SRS-59","_LINK":"SDOC-SRS-59" },
+
+ {"MID":"2b5d74dafd6d43f4bab4c05ed4da6f0d","UID":"SECTION-SRS-Screen-Table-TBL","_LINK":"SECTION-SRS-Screen-Table-TBL" },
+
+ {"MID":"e12b4c5b4f13444d99279ab445df5bcc","UID":"SDOC-SRS-62","_LINK":"SDOC-SRS-62" },
+
+ {"MID":"3c589969eb6a41c19b1dd246dabadbc8","UID":"SECTION-SRS-Screen-Traceability-TR","_LINK":"SECTION-SRS-Screen-Traceability-TR" },
+
+ {"MID":"35d4c1dd30814c2a80918a90081a88b7","UID":"SDOC-SRS-65","_LINK":"SDOC-SRS-65" },
+
+ {"MID":"9d337068b6a940b7a98d40697ea200a8","UID":"SECTION-SRS-Screen-Deep-traceability-DTR","_LINK":"SECTION-SRS-Screen-Deep-traceability-DTR" },
+
+ {"MID":"48bc17d898c94605b17d0267480f57ee","UID":"SDOC-SRS-66","_LINK":"SDOC-SRS-66" },
+
+ {"MID":"ddf15b3113a54107979752ec192e2ded","_LINK":"5.7-Screen-Project-statistics" },
+
+ {"MID":"19f7c2d35237423e950584a4a7aa95a7","UID":"SDOC-SRS-97","_LINK":"SDOC-SRS-97" },
+
+ {"MID":"7968fb7612f64504b5a430ccbffe80f1","UID":"SDOC-SRS-154","_LINK":"SDOC-SRS-154" },
+
+ {"MID":"d84e3a79b3e443cabe96d7c18ea5d322","_LINK":"5.8-Screen-Document-tree-map" },
+
+ {"MID":"1520fa85ed7a4f1aa80c49ed858f402f","UID":"SDOC-SRS-157","_LINK":"SDOC-SRS-157" },
+
+ {"MID":"14ad600308434e6baaeef02d3e90b720","_LINK":"5.9-Screen-Traceability-matrix" },
+
+ {"MID":"167f6fe66d7247a6bf628ed6c1949275","UID":"SDOC-SRS-112","_LINK":"SDOC-SRS-112" },
+
+ {"MID":"544f8ffed8604e63a269a3f953681163","_LINK":"5.10-Screen-Project-tree-diff" },
+
+ {"MID":"aef80cc1a3144564bf23bf3c2a1cfd7f","UID":"SDOC-SRS-111","_LINK":"SDOC-SRS-111" },
+
+ {"MID":"8380fb39beb04d1c9370733bcfafbc01","_LINK":"5.11-Content-search" },
+
+ {"MID":"3e85dd6bf05a4cecb8e070fd81aa333a","UID":"SDOC-SRS-155","_LINK":"SDOC-SRS-155" },
+
+ {"MID":"2d4dc6fc901f4b28aaf414fcfbdfabca","UID":"SECTION-SRS-Requirements-to-source-traceability","_LINK":"SECTION-SRS-Requirements-to-source-traceability" },
+
+ {"MID":"221b544dab2e4b96be124e1caf84a7c2","UID":"SDOC-SRS-33","_LINK":"SDOC-SRS-33" },
+
+ {"MID":"2f63252320d546d88462849b521f45ba","_LINK":"6.2-Language-aware-parsing-of-source-code" },
+
+ {"MID":"79a8080f6e41485f9835ccda067b34bc","UID":"SDOC-SRS-142","_LINK":"SDOC-SRS-142" },
+
+ {"MID":"85a8080f8441485f9111ccda063b34bc","UID":"SDOC-SRS-146","_LINK":"SDOC-SRS-146" },
+
+ {"MID":"3456080f1358485f9bacdcda063b34bc","UID":"SDOC-SRS-147","_LINK":"SDOC-SRS-147" },
+
+ {"MID":"9183080f1358485f9bacdcda0635109","UID":"SDOC-SRS-148","_LINK":"SDOC-SRS-148" },
+
+ {"MID":"bdeda4b89d82446281e2c7c2eae46708","UID":"SDOC-SRS-143","_LINK":"SDOC-SRS-143" },
+
+ {"MID":"aefeb5b89d82446281e2c7c2eae12345","UID":"SDOC-SRS-144","_LINK":"SDOC-SRS-144" },
+
+ {"MID":"5fedbaba39d24da79d074501198ff654","_LINK":"6.5-Forward-linking-from-requirements-to-source-code" },
+
+ {"MID":"21637d9bec434d32bb6b97ba5a4e70e6","UID":"SDOC-SRS-145","_LINK":"SDOC-SRS-145" },
+
+ {"MID":"9c1dd6cbabd44ac680985c403cf710a7","_LINK":"6.6-Source-code-markup-Relations" },
+
+ {"MID":"b9144222a7f3454da2989f494cd9647c","UID":"SDOC-SRS-34","_LINK":"SDOC-SRS-34" },
+
+ {"MID":"61c25cab106e4283b2c6d64bf1db96b2","UID":"SDOC-SRS-124","_LINK":"SDOC-SRS-124" },
+
+ {"MID":"61c23c1b106e4583b2c6d64bf1d296ba","UID":"SDOC-SRS-137","_LINK":"SDOC-SRS-137" },
+
+ {"MID":"86e23c1b106e4adeb2c6d64bf1d29aaa","UID":"SDOC-SRS-140","_LINK":"SDOC-SRS-140" },
+
+ {"MID":"82345cab106e4283b2c7774bf1db96b1","UID":"SDOC-SRS-139","_LINK":"SDOC-SRS-139" },
+
+ {"MID":"11c23c1b105e4583b2c6d64bf1d296cc","UID":"SDOC-SRS-138","_LINK":"SDOC-SRS-138" },
+
+ {"MID":"5ce2ea410dd94927807a258f482483a5","_LINK":"6.7-Source-code-markup-Nodes" },
+
+ {"MID":"f44df3c6a84f4b4e9201a61023446d9c","UID":"SDOC-SRS-141","_LINK":"SDOC-SRS-141" },
+
+ {"MID":"3aeb1eea0dba4041a9161a1a8d291999","UID":"SDOC-SRS-35","_LINK":"SDOC-SRS-35" },
+
+ {"MID":"56ecfb19152e45b09c0e55de2d1d5f05","UID":"SDOC-SRS-36","_LINK":"SDOC-SRS-36" },
+
+ {"MID":"1acdd6ddf9d24dbaa320230402152226","UID":"SECTION-SRS-Export-import-formats","_LINK":"SECTION-SRS-Export-import-formats" },
+
+ {"MID":"ce1d174a4d794250931a5ba519583be6","UID":"SECTION-SRS-RST","_LINK":"SECTION-SRS-RST" },
+
+ {"MID":"2aa615b9cf264e7aad826f4ff466e514","UID":"SDOC-SRS-70","_LINK":"SDOC-SRS-70" },
+
+ {"MID":"6faffbd1d4cc47ea88c08ef38966e5ec","UID":"SDOC-SRS-71","_LINK":"SDOC-SRS-71" },
+
+ {"MID":"a906dfb776334b8985f778f0fe1b79e4","UID":"SECTION-SRS-ReqIF","_LINK":"SECTION-SRS-ReqIF" },
+
+ {"MID":"2bf94015818e4770b2b1947b5fdbb969","UID":"SDOC-SRS-72","_LINK":"SDOC-SRS-72" },
+
+ {"MID":"bb52b698d7a544aca420d606e4e51356","UID":"SDOC-SRS-73","_LINK":"SDOC-SRS-73" },
+
+ {"MID":"0ffda51372b641f6ba460bf5ac8b3627","UID":"SECTION-SRS-Excel","_LINK":"SECTION-SRS-Excel" },
+
+ {"MID":"f7b587f66dda402dbd58768e2740742f","UID":"SDOC-SRS-74","_LINK":"SDOC-SRS-74" },
+
+ {"MID":"97b587f66dda402dbd58768e2740742f","UID":"SDOC-SRS-152","_LINK":"SDOC-SRS-152" },
+
+ {"MID":"5aa75848972249d5bec8a40812b99d86","UID":"SDOC-SRS-134","_LINK":"SDOC-SRS-134" },
+
+ {"MID":"53cfa6296eec45479544e6c5165d7fb9","UID":"SECTION-SRS-Command-line-interface","_LINK":"SECTION-SRS-Command-line-interface" },
+
+ {"MID":"63373c3875404f1c820add84ea057c73","_LINK":"8.1-General-CLI-requirements" },
+
+ {"MID":"598647eed3a446fe93e2c54b197f830e","UID":"SDOC-SRS-103","_LINK":"SDOC-SRS-103" },
+
+ {"MID":"7c6a0efe76b84dcd842ef371796e787e","UID":"SECTION-SRS-Command-Manage","_LINK":"SECTION-SRS-Command-Manage" },
+
+ {"MID":"bea76afe9bf241eaaf5984b54e00ff76","UID":"SECTION-SRS-Command-Auto-UID","_LINK":"SECTION-SRS-Command-Auto-UID" },
+
+ {"MID":"7daa1310876a421f8e39f8ac25b99c1d","UID":"SDOC-SRS-85","_LINK":"SDOC-SRS-85" },
+
+ {"MID":"a0ed7cdd06ec4f0ab6d3ba56cced8c7e","_LINK":"9-Python-API" },
+
+ {"MID":"a20c5b6a021f4dd5a5a5dda2880c1b87","UID":"SDOC-SRS-125","_LINK":"SDOC-SRS-125" },
+
+ {"MID":"590121ded2074757aa1720b4d8013426","_LINK":"10-Web-server" },
+
+ {"MID":"409f462f1f4645c8ad24980727a72521","UID":"SDOC-SRS-126","_LINK":"SDOC-SRS-126" },
+
+ {"MID":"44eb09d0e5b542d5984d234167e6f337","_LINK":"11-User-experience" },
+
+ {"MID":"821c01118a9643a188a4ecc5b0cec6a5","UID":"SECTION-SSRS-Strict-mode-by-default","_LINK":"SECTION-SSRS-Strict-mode-by-default" },
+
+ {"MID":"c4e9dce647654deeab8471d04573f8cb","UID":"SDOC-SRS-6","_LINK":"SDOC-SRS-6" },
+
+ {"MID":"40e7bd8aabdf4cb889e9d7b01b8729e6","UID":"SECTION-SRS-Configurability","_LINK":"SECTION-SRS-Configurability" },
+
+ {"MID":"da446e6d3c6d4b13badd4a47bdbcc5a3","UID":"SDOC-SRS-37","_LINK":"SDOC-SRS-37" },
+
+ {"MID":"a6e70c0619204a26b135d1e5fca45dd7","UID":"SDOC-SRS-39","_LINK":"SDOC-SRS-39" },
+
+ {"MID":"a8a17295d3e24601891c7d19d5ca67d9","UID":"SDOC-SRS-119","_LINK":"SDOC-SRS-119" },
+
+ {"MID":"bb14fb2c46f34cf1a82b417b57e95853","UID":"SECTION-SSRS-Performance","_LINK":"SECTION-SSRS-Performance" },
+
+ {"MID":"acd97ca6b9d2451da53168917d96705e","UID":"SDOC-SRS-1","_LINK":"SDOC-SRS-1" },
+
+ {"MID":"54602f6d120548c8bbd70d1d25113d53","UID":"SDOC-SRS-95","_LINK":"SDOC-SRS-95" },
+
+ {"MID":"6fec2f8c0baa4ddba95bee05ad03a785","UID":"SDOC-SRS-2","_LINK":"SDOC-SRS-2" },
+
+ {"MID":"5f2df631605543d18d57e09bc3791003","UID":"SDOC-SRS-3","_LINK":"SDOC-SRS-3" },
+
+ {"MID":"d0c4828ed8434613aae844481bbef1ca","UID":"SDOC-SRS-4","_LINK":"SDOC-SRS-4" },
+
+ {"MID":"4e014d3291ce460c993a0ff334eff4a7","UID":"SDOC-SRS-5","_LINK":"SDOC-SRS-5" },
+
+ {"MID":"de3a4de44f474784bf233ea7610eac6c","UID":"SECTION-SRS-Quality-requirements","_LINK":"SECTION-SRS-Quality-requirements" },
+
+ {"MID":"cbee3d3e8a9d440abaa58387c342602c","_LINK":"14.1-General-process" },
+
+ {"MID":"27319e3866b8423099774d8770950acd","UID":"SDOC-SRS-133","_LINK":"SDOC-SRS-133" },
+
+ {"MID":"47cec130eb3d4583825355f2635e7011","UID":"SECTION-SRS-Requirements-engineering","_LINK":"SECTION-SRS-Requirements-engineering" },
+
+ {"MID":"d0ab977bbb494cbf818c92a1cab1bef0","UID":"SDOC-SRS-128","_LINK":"SDOC-SRS-128" },
+
+ {"MID":"b3fff332c2e342ec9dd372ebd49cb64d","UID":"SDOC-SRS-91","_LINK":"SDOC-SRS-91" },
+
+ {"MID":"dfbaabc0529f4cc987358ae0563910e9","UID":"SECTION-SRS-Implementation-requirements","_LINK":"SECTION-SRS-Implementation-requirements" },
+
+ {"MID":"5eb734a4b8944531aa75f0b71ef22d52","UID":"SECTION-SRS-Programming-languages","_LINK":"SECTION-SRS-Programming-languages" },
+
+ {"MID":"4053ea6c8f6c4c29b89fea0e39912861","UID":"SDOC-SRS-8","_LINK":"SDOC-SRS-8" },
+
+ {"MID":"131af6457a9f43299306e6dc9fce65a7","UID":"SECTION-SRS-Cross-platform-availability","_LINK":"SECTION-SRS-Cross-platform-availability" },
+
+ {"MID":"ceee07bdc9bd42fc9a4d0e9b4bfc312f","UID":"SDOC-SRS-9","_LINK":"SDOC-SRS-9" },
+
+ {"MID":"f8c7586e1b324480ac0bd153e068350d","UID":"SDOC-SRS-10","_LINK":"SDOC-SRS-10" },
+
+ {"MID":"6af3dbb1e05244579622d3d2a26b5413","UID":"SDOC-SRS-11","_LINK":"SDOC-SRS-11" },
+
+ {"MID":"852396c217184ba98a0d26b92f36fd04","UID":"SECTION-SRS-Implementation-constraints","_LINK":"SECTION-SRS-Implementation-constraints" },
+
+ {"MID":"83d5c896004948b48c3597d58267dafa","UID":"SDOC-SRS-89","_LINK":"SDOC-SRS-89" },
+
+ {"MID":"b22bf982e73246a79a5ba4ae653d21e5","UID":"SDOC-SRS-14","_LINK":"SDOC-SRS-14" },
+
+ {"MID":"309e4108c1fa47e99d4331af642f3b81","UID":"SDOC-SRS-15","_LINK":"SDOC-SRS-15" },
+
+ {"MID":"b9cacb97a045418385c7f870b23ac063","UID":"SDOC-SRS-16","_LINK":"SDOC-SRS-16" },
+
+ {"MID":"70f05a744a0546909dc5b69de88ad41f","UID":"SDOC-SRS-87","_LINK":"SDOC-SRS-87" },
+
+ {"MID":"7d68821750a54cb5833b608cfc278f47","UID":"SDOC-SRS-88","_LINK":"SDOC-SRS-88" },
+
+ {"MID":"e4e5b9934e074cdb9567fa197db20a4a","UID":"SECTION-SRS-Coding-constraints","_LINK":"SECTION-SRS-Coding-constraints" },
+
+ {"MID":"61d96cd1d03e40c48187ee67ac0b65f6","UID":"SDOC-SRS-40","_LINK":"SDOC-SRS-40" },
+
+ {"MID":"72b5b0c925cf4ef49749b7e466675df1","UID":"SDOC-SRS-41","_LINK":"SDOC-SRS-41" },
+
+ {"MID":"61e87567580045378d970b327d218cac","UID":"SECTION-SRS-Linting","_LINK":"SECTION-SRS-Linting" },
+
+ {"MID":"6c0163c56ade49faa353ec06cbd676cd","UID":"SDOC-SRS-42","_LINK":"SDOC-SRS-42" },
+
+ {"MID":"3029f97a1276499dbbd5d7c71691908e","UID":"SECTION-SRS-Static-analysis","_LINK":"SECTION-SRS-Static-analysis" },
+
+ {"MID":"2cc9b494ca6248058b6bf63b6e2c1cfa","UID":"SDOC-SRS-43","_LINK":"SDOC-SRS-43" },
+
+ {"MID":"3aba8ca86d404ba9a063ce125489f35b","UID":"SECTION-SRS-Testing","_LINK":"SECTION-SRS-Testing" },
+
+ {"MID":"2731c64ab32146eeb4b8167df4a34540","UID":"SDOC-SRS-44","_LINK":"SDOC-SRS-44" },
+
+ {"MID":"70ef3986cfc4437bbb10288d3b55958c","UID":"SDOC-SRS-45","_LINK":"SDOC-SRS-45" },
+
+ {"MID":"a42c65f1a53b4c9bb50bc2a1ecb855cb","UID":"SDOC-SRS-46","_LINK":"SDOC-SRS-46" },
+
+ {"MID":"c90f35ab9a7f4c29a418557151878b9f","UID":"SDOC-SRS-47","_LINK":"SDOC-SRS-47" },
+
+ {"MID":"83bdb9731e78431cb48d584d279443b4","_LINK":"15-Code-hosting-and-distribution" },
+
+ {"MID":"dbd186fae9624fd6af8aeb55edfaa43b","UID":"SECTION-SRS-Code-hosting","_LINK":"SECTION-SRS-Code-hosting" },
+
+ {"MID":"b112c60bc2f34114ab1f3361a1a10a00","UID":"SDOC-SRS-12","_LINK":"SDOC-SRS-12" },
+
+ {"MID":"bd949cbbe07c4cb29492ea0c8e5c1eec","UID":"SDOC-SRS-118","_LINK":"SDOC-SRS-118" }, ],
+ "strictdoc/docs/strictdoc_24_development_plan.html": [
+
+
+ {"MID":"e776a9eb7ba0455eb589787028aa0529","_LINK":"None-Development-Plan" },
+
+ {"MID":"2ba509874f1744cf899643b58a6a2095","_LINK":"2ba509874f1744cf899643b58a6a2095" },
+
+ {"MID":"24b0bc5efe074a419b441900d30b2876","_LINK":"1-Project-goals" },
+
+ {"MID":"bdbd5aecefdc41bca1c88b9bce71d512","_LINK":"bdbd5aecefdc41bca1c88b9bce71d512" },
+
+ {"MID":"f1e3c17829fd4eebbd390fceaeb95619","UID":"SECTION-DP-Project-milestones","_LINK":"SECTION-DP-Project-milestones" },
+
+ {"MID":"fd9294fdd2b546de993f649767371394","_LINK":"fd9294fdd2b546de993f649767371394" },
+
+ {"MID":"bf9f3f05501140da8d35cde39493c72f","_LINK":"2.1-The-roadmap-diagram" },
+
+ {"MID":"53e101acb20e44e89de27f0f77c5f0cb","_LINK":"53e101acb20e44e89de27f0f77c5f0cb" },
+
+ {"MID":"625560c790a3492eaf45466b787602d7","_LINK":"3-Versioning" },
+
+ {"MID":"ae2a2af6e3f24f65845c6c37ea7da2e2","_LINK":"ae2a2af6e3f24f65845c6c37ea7da2e2" },
+
+ {"MID":"ef6bde37e1c54f49afdbd3c6785fd01c","_LINK":"4-Quality" },
+
+ {"MID":"14d0e79fcadc43f1a1cee2d66ae6b763","_LINK":"14d0e79fcadc43f1a1cee2d66ae6b763" },
+
+ {"MID":"bc49b1e28fff4386b3bf5788a6686a79","_LINK":"4.1-Linting-of-code" },
+
+ {"MID":"f6de78d4a95b4970ab55563e18472a92","_LINK":"f6de78d4a95b4970ab55563e18472a92" },
+
+ {"MID":"38ce17138405490b80e06037b40dc49d","_LINK":"4.2-Static-analysis" },
+
+ {"MID":"ad63541e341d4648ab59b4a0817a7e3c","_LINK":"ad63541e341d4648ab59b4a0817a7e3c" },
+
+ {"MID":"2834756354a7420499d0deecfe0ee9c4","_LINK":"4.3-Testing" },
+
+ {"MID":"ee541e7062704b3f919bcaac2bce2723","_LINK":"ee541e7062704b3f919bcaac2bce2723" },
+
+ {"MID":"2004550abd54486d9aa5f98282eef6e1","_LINK":"4.4-Traceability-between-StrictDoc-requirements-code-and-tests" },
+
+ {"MID":"f829d28d2e3d4bcaa38f44ffb1ac0373","_LINK":"f829d28d2e3d4bcaa38f44ffb1ac0373" },
+
+ {"MID":"30b874ab3eac4d429633537e1e89677f","_LINK":"4.5-Continuous-integration-CI" },
+
+ {"MID":"85e3915270f144c7a76ccfa0e088d93d","_LINK":"85e3915270f144c7a76ccfa0e088d93d" },
+
+ {"MID":"2ae3a8822a424a9e8ad6976c2476d109","_LINK":"5-Python-baseline" },
+
+ {"MID":"081ee6266bab4a3a80f290c95e055a25","_LINK":"081ee6266bab4a3a80f290c95e055a25" }, ],
+ "strictdoc/docs/strictdoc_25_design.html": [
+
+
+ {"MID":"8e68536f7d4047ada15d3a3043580c4a","UID":"SDOC_DD","_LINK":"SDOC_DD" },
+
+ {"MID":"2c006e9044074d239db4a45328633657","_LINK":"2c006e9044074d239db4a45328633657" },
+
+ {"MID":"a74f4e7328714765b5e051768ca8383d","_LINK":"1-Overview" },
+
+ {"MID":"23937f96ac8e437d81686071cc42d6bf","_LINK":"23937f96ac8e437d81686071cc42d6bf" },
+
+ {"MID":"f296843b2027457f851a159abafc97e3","_LINK":"2-Building-blocks" },
+
+ {"MID":"bae7db5591fe418a857af4fb02ad4fec","_LINK":"bae7db5591fe418a857af4fb02ad4fec" },
+
+ {"MID":"5328a6f4c8544f5e92a91279b5b2c0df","UID":"SECTION-DD-High-level-architecture","_LINK":"SECTION-DD-High-level-architecture" },
+
+ {"MID":"dcb6369b8d0949f0b06c9ee5b2188b12","_LINK":"dcb6369b8d0949f0b06c9ee5b2188b12" },
+
+ {"MID":"9b81ed50014c412bb617e90552e58879","_LINK":"4-StrictDoc-command-line-application" },
+
+ {"MID":"0e0fca629004496084dbe5e217874c36","_LINK":"0e0fca629004496084dbe5e217874c36" },
+
+ {"MID":"dbcfa8a98e4f4928b0b35938d57dd644","_LINK":"5-StrictDoc-web-application" },
+
+ {"MID":"f84c0efa27954e44a8b5c1dd3517f90f","_LINK":"f84c0efa27954e44a8b5c1dd3517f90f" },
+
+ {"MID":"dd2bd75fdffe49a1a0299b804538329c","_LINK":"5.1-The-HTML-Over-the-Wire-Hotwire-architecture" },
+
+ {"MID":"5577da2187294eb986ec84d9fe26bbdf","_LINK":"5577da2187294eb986ec84d9fe26bbdf" },
+
+ {"MID":"50f1db3236fa426ea5904974ee724939","_LINK":"6-Static-HTML-search" },
+
+ {"MID":"5fedd9aac1684adc8fe1f3b87557345d","UID":"SDOC-SRS-156","_LINK":"SDOC-SRS-156" },
+
+ {"MID":"108af17c077c48bea04557c9d325e924","_LINK":"7-Parsing-SDoc-files" },
+
+ {"MID":"8a926f0a67424a1eb5db73bb5abca0cd","_LINK":"8a926f0a67424a1eb5db73bb5abca0cd" },
+
+ {"MID":"4db723c7ae2c4350b2f184783cb638e7","UID":"SECTION-DD-Caching-artifacts","_LINK":"SECTION-DD-Caching-artifacts" },
+
+ {"MID":"d351d1bf6c2a48d88e9b9bdc50e029ff","_LINK":"d351d1bf6c2a48d88e9b9bdc50e029ff" },
+
+ {"MID":"4b904b71438c47fcac8aba14df2dd7c0","_LINK":"9-HTML-escaping" },
+
+ {"MID":"e8a03713c7f644698d9a72cc79b2a299","_LINK":"e8a03713c7f644698d9a72cc79b2a299" },
+
+ {"MID":"92e8709709614f0f9ccdf702799bf56c","_LINK":"10-ReqIF-interface" },
+
+ {"MID":"abe8709709614f0f9ccdf702799bf511","UID":"SDOC-SRS-153","_LINK":"SDOC-SRS-153" }, ],
+ "strictdoc/docs/strictdoc_28_Backlog.html": [
+
+
+ {"MID":"cabef7629dda4f2fb34255d01fea8d5f","_LINK":"None-StrictDoc-Backlog" },
+
+ {"MID":"35bc1e28ec724aefbcff864c89399877","_LINK":"35bc1e28ec724aefbcff864c89399877" },
+
+ {"MID":"d1e697dea73144c48a4b88d0d784a517","UID":"SECTION-SB-Open-source-requirements-tool-challenges","_LINK":"SECTION-SB-Open-source-requirements-tool-challenges" },
+
+ {"MID":"d65fe32e8ea444ceb99c174bfc06df7d","_LINK":"d65fe32e8ea444ceb99c174bfc06df7d" },
+
+ {"MID":"fc76b207c152433888a86a166f58a425","UID":"SDOC-SRS-13","_LINK":"SDOC-SRS-13" },
+
+ {"MID":"7614a9f4f7bd4b1c9899995ac3d1e6ad","UID":"SECTION-SB-Backlog","_LINK":"SECTION-SB-Backlog" },
+
+ {"MID":"e61e7224e27d41ceacad9bf6051bd6f0","UID":"SDOC-BACKLOG-6","_LINK":"SDOC-BACKLOG-6" },
+
+ {"MID":"07a9636655314912a996ecf5692ae3d5","UID":"SDOC-SRS-86","_LINK":"SDOC-SRS-86" },
+
+ {"MID":"0425151bf3944e0ebc1c5acabcb35905","UID":"SECTION-SRS-Screen-Project-home","_LINK":"SECTION-SRS-Screen-Project-home" },
+
+ {"MID":"0a158ddac310483489ef08f618ba8741","UID":"SDOC-SRS-52","_LINK":"SDOC-SRS-52" },
+
+ {"MID":"1d8a2c3cf8c24e1b92fe212ab7efacf2","_LINK":"2.4-Screen-Traceability-navigator" },
+
+ {"MID":"dbfe92e9ec3b44e9a3e1c9e89a0e9ef5","UID":"SDOC-SRS-113","_LINK":"SDOC-SRS-113" },
+
+ {"MID":"2654d541d5ce4cb6ad9fcfe2eaa9abb4","UID":"SECTION-SB-Formal-modeling","_LINK":"SECTION-SB-Formal-modeling" },
+
+ {"MID":"5958a5c0aad8486b84ad31bc014d4ad3","UID":"SDOC-RMC-27","_LINK":"SDOC-RMC-27" },
+
+ {"MID":"99e84f704c074cf28de51ce6fb183a66","UID":"SDOC-RMC-29","_LINK":"SDOC-RMC-29" },
+
+ {"MID":"44b30591f6674ede821324fe527babd9","UID":"SDOC-RMC-55","_LINK":"SDOC-RMC-55" },
+
+ {"MID":"045aee37b0a24b3cb62cabd8b614aaf7","UID":"SDOC-RMC-28","_LINK":"SDOC-RMC-28" },
+
+ {"MID":"7e0fd5af118b4f5d8ecbf0d8ef3841e6","UID":"SDOC-RMC-30","_LINK":"SDOC-RMC-30" },
+
+ {"MID":"061392f275b04c93b664faad9ed4f483","UID":"SECTION-SRS-LaTeX-export","_LINK":"SECTION-SRS-LaTeX-export" },
+
+ {"MID":"9ec7f471ccb243ea9d86cf2756403b8f","UID":"SDOC-SRS-76","_LINK":"SDOC-SRS-76" },
+
+ {"MID":"5a0304abcd8a44dab5d032dce6625a5d","UID":"SDOC-BACKLOG-1","_LINK":"SDOC-BACKLOG-1" },
+
+ {"MID":"162a3da4d9d74c15b5078c9859657ce3","UID":"SDOC-BACKLOG-2","_LINK":"SDOC-BACKLOG-2" },
+
+ {"MID":"06f16ede826749a389c8d7de9828e0eb","UID":"SDOC-BACKLOG-3","_LINK":"SDOC-BACKLOG-3" },
+
+ {"MID":"0e69828e1d914e20852aef7cfc4e87c4","UID":"SDOC-BACKLOG-9","_LINK":"SDOC-BACKLOG-9" },
+
+ {"MID":"34246811634c493dbc771ae4c8bc3b14","UID":"SDOC-BACKLOG-4","_LINK":"SDOC-BACKLOG-4" },
+
+ {"MID":"3f50a97bc70842dbabeea911f653ef90","UID":"SDOC-BACKLOG-7","_LINK":"SDOC-BACKLOG-7" },
+
+ {"MID":"72285f9b09de48a29fef8f85431e4a94","UID":"SDOC-BACKLOG-8","_LINK":"SDOC-BACKLOG-8" },
+
+ {"MID":"bdedcdd91c7f4efb8787b5a82cfec49b","UID":"SDOC-SRS-114","_LINK":"SDOC-SRS-114" },
+
+ {"MID":"478c38d2cca94107b18fe3dc5b8bfefd","_LINK":"2.15-Multi-user-workflow" },
+
+ {"MID":"f97dc050ddab4a08bf1689200118faaa","UID":"SDOC-SRS-123","_LINK":"SDOC-SRS-123" },
+
+ {"MID":"e5b2aff0c1db4b11a8c75c278813300b","UID":"SDOC-SRS-130","_LINK":"SDOC-SRS-130" },
+
+ {"MID":"440f0bc311b84421a7e8bea9dfd2448b","UID":"SDOC-SRS-131","_LINK":"SDOC-SRS-131" },
+
+ {"MID":"caecd704ed634d718deff07ba0db7fa6","UID":"SDOC-SRS-116","_LINK":"SDOC-SRS-116" },
+
+ {"MID":"b74a7a3209d247f6b357513b0cce5000","UID":"SDOC-SRS-121","_LINK":"SDOC-SRS-121" },
+
+ {"MID":"fa7fd8fd3a694d8e93953fd60e19fdde","UID":"SDOC-SRS-61","_LINK":"SDOC-SRS-61" },
+
+ {"MID":"7a06d1433e4c4b0eaf55ede14507eac9","UID":"SDOC-SRS-94","_LINK":"SDOC-SRS-94" },
+
+ {"MID":"45b8513623744776899abfbf99c95286","UID":"SDOC-SRS-58","_LINK":"SDOC-SRS-58" },
+
+ {"MID":"c02a65f2716f4a86b8f83e3a7b4cd31c","UID":"SDOC-SRS-60","_LINK":"SDOC-SRS-60" },
+
+ {"MID":"7aa5316dd056465e97044e221412290b","UID":"SDOC-SRS-63","_LINK":"SDOC-SRS-63" },
+
+ {"MID":"229378602d1847cb83c61ab3e97bb22b","UID":"SDOC-SRS-64","_LINK":"SDOC-SRS-64" },
+
+ {"MID":"b3472533d57145bc9790724efe56075c","_LINK":"2.24-Screen-Impact-analysis" },
+
+ {"MID":"f5feb38777064d9db939279d32f79130","UID":"SDOC-SRS-117","_LINK":"SDOC-SRS-117" },
+
+ {"MID":"a7c504087df04cedb5541d83ed988e9b","UID":"SDOC-SRS-75","_LINK":"SDOC-SRS-75" },
+
+ {"MID":"4a49c79a1bdd4d4aae5f62bc1d2a56d0","UID":"SECTION-SB-Backlog-Web-based-user-interface","_LINK":"SECTION-SB-Backlog-Web-based-user-interface" },
+
+ {"MID":"d10cddd846de4961bbb0bc8b8c6550d3","_LINK":"d10cddd846de4961bbb0bc8b8c6550d3" },
+
+ {"MID":"866a55f2e47b477ebcd52ea57da4f037","UID":"SECTION-SB-Backlog-Nice-to-have","_LINK":"SECTION-SB-Backlog-Nice-to-have" },
+
+ {"MID":"d02e104a518c4627ac918a33ad165c96","_LINK":"d02e104a518c4627ac918a33ad165c96" },
+
+ {"MID":"eb1fab2bbea541c8b00f70780326c9fc","UID":"SECTION-SB-Backlog-Technical-debt","_LINK":"SECTION-SB-Backlog-Technical-debt" },
+
+ {"MID":"85e94802132048d29ca73cf2096c6758","_LINK":"85e94802132048d29ca73cf2096c6758" },
+
+ {"MID":"6ef8c2ad683d46af948674727c7a52b4","UID":"SECTION-SB-Open-questions","_LINK":"SECTION-SB-Open-questions" },
+
+ {"MID":"717df91623014fb98ba34ab8173b94ab","UID":"SECTION-SB-One-or-many-input-sdoc-trees","_LINK":"SECTION-SB-One-or-many-input-sdoc-trees" },
+
+ {"MID":"b778a18ede89464c936be2b2af492e24","_LINK":"b778a18ede89464c936be2b2af492e24" }, ],
+ "strictdoc/docs/strictdoc_30_credits.html": [
+
+
+ {"MID":"d92baa6b8cf745a2ab6be86616b06277","_LINK":"None-Credits" },
+
+ {"MID":"18cf0af34c194590b3eb391c2ef94074","_LINK":"18cf0af34c194590b3eb391c2ef94074" },
+
+ {"MID":"c89b5ba9c6dc427497647b64048a2c98","_LINK":"1-Contributions-to-StrictDoc" },
+
+ {"MID":"e6de83e242bc4aea96622a2e7585f135","_LINK":"e6de83e242bc4aea96622a2e7585f135" },
+
+ {"MID":"4d59a5df65d547e685cb491937793f69","_LINK":"2-Open-source-software" },
+
+ {"MID":"4428ac9ec3504dda9f1e1e845ffb3c75","_LINK":"4428ac9ec3504dda9f1e1e845ffb3c75" },
+
+ {"MID":"2da7450f8b804a7a8494921486bd4d8e","_LINK":"3-Hosting-and-Continuous-Integration" },
+
+ {"MID":"5b702e6f9b714e458b059912ca8e196a","_LINK":"5b702e6f9b714e458b059912ca8e196a" },
+
+ {"MID":"43ccb6448b9d4b65a2c40df54d1707aa","_LINK":"4-Free-and-commercial-IDEs-by-JetBrains" },
+
+ {"MID":"b4729e592d104fe3818c8949615ffef9","_LINK":"b4729e592d104fe3818c8949615ffef9" }, ],
+ "strictdoc/docs_extra/DO178_requirements.html": [
+
+
+ {"MID":"b3727ea826c24d42a84e88983e7c1e24","_LINK":"None-Technical-Note-DO-178C-requirements-tool-requirements" },
+
+ {"MID":"fc77215d50134f17aa242b4df7310099","_LINK":"fc77215d50134f17aa242b4df7310099" },
+
+ {"MID":"6be4dbe02b4346df9849eaa6fe077e0e","UID":"SECTION-DR-Already-implemented-features","_LINK":"SECTION-DR-Already-implemented-features" },
+
+ {"MID":"af14393406e64ab6b2911eefa4358f33","UID":"DO178-1","_LINK":"DO178-1" },
+
+ {"MID":"0a19cae3756a4d2f9f0be9e57c44a8fa","UID":"DO178-2","_LINK":"DO178-2" },
+
+ {"MID":"dd075d6cd4fb4ad2b731a9b8068efade","UID":"DO178-14","_LINK":"DO178-14" },
+
+ {"MID":"03346e43cd0b43529cc3b958a00d8d35","UID":"DO178-3","_LINK":"DO178-3" },
+
+ {"MID":"4f0809d49292413eb621a47a8b405bc7","UID":"DO178-4","_LINK":"DO178-4" },
+
+ {"MID":"c74bba92cec34bf7b1046689c2dfc54c","UID":"DO178-5","_LINK":"DO178-5" },
+
+ {"MID":"8b73ce9efcc840b2be272d5aaef08e70","UID":"DO178-6","_LINK":"DO178-6" },
+
+ {"MID":"8c654ff659a94cceb0c7a52bc8ae4073","UID":"DO178-8","_LINK":"DO178-8" },
+
+ {"MID":"cfdb3867a4a64b3eb9405e998c11ae72","UID":"DO178-7","_LINK":"DO178-7" },
+
+ {"MID":"40d4a56263d0420691dbde5d7889895a","UID":"DO178-13","_LINK":"DO178-13" },
+
+ {"MID":"8bd26640450f448c8228464223c21373","UID":"DO178-9","_LINK":"DO178-9" },
+
+ {"MID":"09f3e3faa1b84aafb19f26e22ab06c95","UID":"SECTION-DR-Needs-discussion","_LINK":"SECTION-DR-Needs-discussion" },
+
+ {"MID":"db4336a8f119443cae6a70d74a0601da","UID":"DO178-19","_LINK":"DO178-19" },
+
+ {"MID":"7d18b7674050495c935dc4669dfb260e","UID":"DO178-15","_LINK":"DO178-15" },
+
+ {"MID":"b0c13e71074242ab91d6344514b82657","UID":"DO178-10","_LINK":"DO178-10" },
+
+ {"MID":"7e8a475859084e9d95eda3f2c1381ae7","UID":"DO178-11","_LINK":"DO178-11" },
+
+ {"MID":"23c11790799c4457804bcb9d6288931e","UID":"DO178-12","_LINK":"DO178-12" },
+
+ {"MID":"a1fb2f7cd7cd4c8eb33c3407a791fd88","UID":"DO178-16","_LINK":"DO178-16" },
+
+ {"MID":"756503f4934a4aed81dfe090b2538e2a","UID":"DO178-17","_LINK":"DO178-17" },
+
+ {"MID":"8120b4f6be4e4ecd83c0b69a3424e0be","UID":"DO178-18","_LINK":"DO178-18" }, ],
+ "strictdoc/docs_extra/Zephyr_requirements.html": [
+
+
+ {"MID":"2e7deb9808bb42879e7463b1d7ac9bba","_LINK":"None-Technical-Note-Zephyr-requirements-tool-requirements" },
+
+ {"MID":"68e87901205c4b0dbb6a0071479330b5","UID":"ZEP-1","_LINK":"ZEP-1" },
+
+ {"MID":"36415af620f645388af4dc51c2a19b97","UID":"ZEP-2","_LINK":"ZEP-2" },
+
+ {"MID":"7a9e26240f5c4fe29143cf3348ac3d3b","UID":"ZEP-3","_LINK":"ZEP-3" },
+
+ {"MID":"a5928d6204a84d02a3c367d6dbc54092","UID":"ZEP-4","_LINK":"ZEP-4" },
+
+ {"MID":"55bbe693d12d4e00956d41a837ef15ef","UID":"ZEP-5","_LINK":"ZEP-5" },
+
+ {"MID":"b58c387f3a2d4cf6a540e279dbe49e47","UID":"ZEP-6","_LINK":"ZEP-6" },
+
+ {"MID":"17a141add32f4d7696b5a74b6507b9aa","UID":"ZEP-7","_LINK":"ZEP-7" },
+
+ {"MID":"d0d258d8640443578c7ec508c014b50d","UID":"ZEP-8","_LINK":"ZEP-8" },
+
+ {"MID":"611546bf2409417e8844f93854d54268","UID":"ZEP-9","_LINK":"ZEP-9" },
+
+ {"MID":"f1f6da87da5c49d1b8c3441b14863975","UID":"ZEP-10","_LINK":"ZEP-10" },
+
+ {"MID":"55cbd9b658164414adb0c13b0446e3f7","UID":"ZEP-11","_LINK":"ZEP-11" },
+
+ {"MID":"a2930225168147808e6554a4da49aeb4","UID":"ZEP-12","_LINK":"ZEP-12" },
+
+ {"MID":"2614d6673a594da995df672e8943839e","UID":"ZEP-13","_LINK":"ZEP-13" },
+
+ {"MID":"a92a28ce3bcb4b3590f36e778a604ccb","UID":"ZEP-14","_LINK":"ZEP-14" },
+
+ {"MID":"b74919612283422a9e139418a20926c6","UID":"ZEP-15","_LINK":"ZEP-15" }, ],
+};
diff --git a/tests/fuzz/20_L1_Open_Requirements_Tool_202511/assets/project_tree.css b/tests/fuzz/20_L1_Open_Requirements_Tool_202511/assets/project_tree.css
new file mode 100644
index 0000000..940d06b
--- /dev/null
+++ b/tests/fuzz/20_L1_Open_Requirements_Tool_202511/assets/project_tree.css
@@ -0,0 +1,218 @@
+
+/* tree */
+.project_tree {
+ position: relative;
+ /* width: -moz-fit-content;
+ width: fit-content; */
+ /* margin: 0 auto; */
+}
+
+.project_tree details>summary {
+ list-style: none;
+}
+
+.project_tree summary::-webkit-details-marker {
+ display: none
+}
+
+/* folder */
+
+.project_tree-folder {
+ border: var(--base-border);
+ border-radius: calc(0.5 * var(--base-rhythm));
+ overflow: hidden;
+ position: relative;
+ padding-left: var(--base-rhythm);
+ padding-right: var(--base-rhythm);
+ background: var(--color-bg-secondary);
+}
+
+.project_tree-folder[open] {
+ background: transparent;
+}
+
+.project_tree-folder.source {
+ padding-right: 0;
+ border-right: none;
+ border-bottom: none;
+}
+
+.project_tree-folder summary {
+ position: relative;
+ cursor: pointer;
+ user-select: none;
+}
+
+.project_tree-folder-title {
+ font-weight: bold;
+ display: flex;
+ column-gap: calc(0.5 * var(--base-rhythm));
+ font-size: 0.85rem;
+ line-height: 1.2;
+ color: #666;
+ padding: calc(0.5 * var(--base-rhythm));
+ position: relative;
+}
+
+.project_tree-folder-title::before,
+.project_tree-folder-title::after {
+ content: '';
+ position: absolute;
+ top: 0;
+ right: -20px;
+ left: -20px;
+ bottom: 0;
+}
+
+.project_tree-folder-title::after {
+ background: var(--color-bg-secondary);
+}
+
+.project_tree-folder summary:hover > .project_tree-folder-title::before {
+ background: var(--color-bg-secondary);
+}
+
+.project_tree-folder summary:hover > .project_tree-folder-title,
+.project_tree-folder summary:hover::after {
+ color: var(--color-fg-accent);
+}
+
+/* .icon_collapse_expand is class inside SVG */
+.project_tree-folder-title .icon_collapse_expand {
+ margin-left: auto;
+}
+/* .collapsed and .expanded are classes inside SVG .icon_collapse */
+.project_tree-folder > summary .icon_collapse_expand .collapsed {
+ display: initial;
+}
+.project_tree-folder > summary .icon_collapse_expand .expanded {
+ display: none;
+}
+.project_tree-folder[open] > summary .icon_collapse_expand .expanded {
+ display: initial;
+}
+.project_tree-folder[open] > summary .icon_collapse_expand .collapsed {
+ display: none;
+}
+
+.project_tree-folder-content {
+ display: flex;
+ flex-direction: column;
+ justify-content: space-between;
+ gap: var(--base-rhythm);
+ padding-top: var(--base-rhythm);
+ padding-bottom: var(--base-rhythm);
+}
+
+/* file */
+
+.project_tree-file {
+ display: flex;
+ column-gap: var(--base-rhythm);
+ padding: calc(0.5 * var(--base-rhythm));
+ border-radius: calc(0.5 * var(--base-rhythm));
+ transition: background .3s;
+ border: 1px solid rgba(255,255,255,0);
+}
+
+.project_tree-file:not([href]):hover {
+ border: 1px solid rgba(255,255,255,0.75);
+ background: rgba(0,0,0,0.01);
+}
+
+.project_tree-file[href]:hover {
+ background: rgba(255,255,255,0.5);
+}
+
+.project_tree-file[href]:hover .project_tree-file-icon,
+.project_tree-file[href]:hover .project_tree-file-title {
+ color: var(--color-fg-accent);
+}
+
+.project_tree-file-details {
+ display: block;
+}
+
+.project_tree-file-icon {
+ line-height: 0;
+}
+
+.project_tree-file-title {
+ font-size: 1em;
+ font-weight: 500;
+ line-height: 1.2;
+ transition: color .2s;
+}
+
+.project_tree-file-icon,
+.project_tree-file-title {
+ color: var(--color-fg-secondary);
+}
+
+.project_tree-file[href] .project_tree-file-icon,
+.project_tree-file[href] .project_tree-file-title {
+ color: var(--color-fg-main);
+}
+
+.project_tree-file-name {
+ font-size: 0.85rem;
+ line-height: 1.2;
+ color: var(--color-fg-secondary);
+ margin-top: 0.25rem;
+}
+
+.project_tree-file-aside {
+ margin-left: auto;
+}
+
+/* dashboard */
+
+.dashboard {
+ display: flex;
+ align-items: flex-start;
+ gap: var(--base-rhythm);
+}
+
+.dashboard-main {
+ flex-grow: 1;
+}
+
+.dashboard-aside {
+ width: 30%;
+ /* max-width: 300px; */
+ font-size: 0.75rem;
+ display: flex;
+ gap: var(--base-rhythm);
+ flex-direction: column;
+}
+
+.dashboard-block:empty {
+ display: none;
+}
+
+.dashboard-block {
+ border: var(--base-border);
+ border-radius: calc(0.5 * var(--base-rhythm));
+ overflow: hidden;
+ position: relative;
+ padding: var(--base-rhythm);
+}
+
+.dashboard-block-title {
+ font-weight: 600;
+ position: relative;
+ top: calc(-1 * var(--base-rhythm));
+ color: var(--color-fg-secondary);
+ padding: calc(0.5 * var(--base-rhythm)) 0;
+}
+
+.dashboard-block-title::after {
+ content: '';
+ position: absolute;
+ top: -20px;
+ left: -20px;
+ right: -20px;
+ bottom: 0;
+ background-color: rgba(0,0,0,0.025);
+ border-bottom: var(--base-border);
+}
diff --git a/tests/fuzz/20_L1_Open_Requirements_Tool_202511/assets/project_tree.js b/tests/fuzz/20_L1_Open_Requirements_Tool_202511/assets/project_tree.js
new file mode 100644
index 0000000..79a48c9
--- /dev/null
+++ b/tests/fuzz/20_L1_Open_Requirements_Tool_202511/assets/project_tree.js
@@ -0,0 +1,373 @@
+const FRAME_SELECTOR = '#frame_project_tree';
+const SWITCH_SELECTOR = '#project_tree_controls';
+const FRAGMENT_ATTR = 'included-document';
+const FRAGMENT_SELECTOR = `.project_tree-file[${FRAGMENT_ATTR}]`;
+const FILE_SELECTOR = `.project_tree-file`;
+const FOLDER_SELECTOR = `.project_tree-folder`;
+
+// This class Switch was taken
+// from strictdoc/export/html/_static/source-code-coverage.js
+// and improved a bit:
+class Switch {
+ constructor({
+ callback,
+ labelText,
+ checked,
+ componentClass,
+ colorOn,
+ colorOff,
+ size,
+ stroke,
+ units,
+ position,
+ topPosition,
+ leftPosition,
+ rightPosition,
+ bottomPosition,
+ dataTestID,
+ }) {
+ this.colorOn = colorOn || 'rgb(242, 100, 42)';
+ this.colorOff = colorOff || 'rgb(200, 200, 200)';
+ this.labelInitialText = labelText || '';
+ this.checked = (checked === false) ? false : true;
+
+ this.dataTestID = dataTestID || 'std-switch';
+ this.componentClass = componentClass || 'std-switch-scc';
+ this.size = size || 0.75;
+ this.stroke = stroke || 0.25;
+ this.units = units || 'rem';
+
+ this.topPosition = topPosition || 'unset',
+ this.leftPosition = leftPosition || 'unset',
+ this.rightPosition = rightPosition || 'unset',
+ this.bottomPosition = bottomPosition || 'unset',
+ this.position = position || 'static',
+
+ this.controlLabelTextSpan = document.createElement('span');
+ this.callback = callback;
+ }
+
+ create() {
+ const block = document.createElement('div');
+ block.classList.add(this.componentClass);
+ const label = document.createElement('label');
+ label.classList.add(`${this.componentClass}__label`);
+ const input = document.createElement('input');
+ input.classList.add(`${this.componentClass}__input`);
+ input.type = 'checkbox';
+ input.checked = this.checked;
+ const slider = document.createElement('span');
+ slider.classList.add(`${this.componentClass}__slider`);
+
+ label.append(input, slider, this.controlLabelTextSpan);
+ block.append(label);
+
+ this.insertStyle();
+ this.updateLabelText(this.labelInitialText);
+ input.addEventListener('change', () => this.callback(input.checked));
+
+ label.setAttribute('data-testid', this.dataTestID);
+
+ return block;
+ }
+
+ updateLabelText(text) {
+ this.controlLabelTextSpan.innerHTML = text;
+ }
+
+ insertStyle() {
+
+ const css = `
+ .${this.componentClass} {
+ display: inline-block;
+ line-height: 0;
+ position: ${this.position};
+ top: ${this.topPosition};
+ left: ${this.leftPosition};
+ right: ${this.rightPosition};
+ bottom: ${this.bottomPosition};
+ }
+ .${this.componentClass}__label {
+ display: inline-flex;
+ column-gap: 8px;
+ line-height: ${this.size * 1.6}${this.units};
+ line-height: 1.25;
+ align-items: flex-start;
+ justify-content: flex-start;
+ user-select: none;
+ cursor: pointer;
+ font-size: small;
+ }
+ .${this.componentClass}__input {
+ opacity: 0;
+ width: 0;
+ height: 0;
+ position: absolute;
+ }
+ .${this.componentClass}__slider {
+ position: relative;
+ cursor: pointer;
+ background-color: ${this.colorOff};
+ -webkit-transition: .4s;
+ transition: .4s;
+ display: inline-block;
+ width: ${this.size * 2 + this.stroke * 2}${this.units};
+ min-width: ${this.size * 2 + this.stroke * 2}${this.units};
+ height: ${this.size + this.stroke * 2}${this.units};
+ margin-right: ${this.size * 0.5}${this.units};
+ border-radius: ${this.size * 0.5 + this.stroke}${this.units};
+ }
+ .${this.componentClass}__slider::before {
+ position: absolute;
+ content: "";
+ height: ${this.size}${this.units};
+ width: ${this.size}${this.units};
+ left: ${this.stroke}${this.units};
+ bottom: ${this.stroke}${this.units};
+ background-color: white;
+ -webkit-transition: .4s;
+ transition: .4s;
+ border-radius: 50%;
+ }
+ input:checked + .${this.componentClass}__slider {
+ background-color: ${this.colorOn};
+ }
+ input:focus + .${this.componentClass}__slider {
+ box-shadow: 0 0 1px ${this.colorOn};
+ }
+ input:checked + .${this.componentClass}__slider::before {
+ -webkit-transform: translateX(${this.size}${this.units});
+ -ms-transform: translateX(${this.size}${this.units});
+ transform: translateX(${this.size}${this.units});
+ }
+ `;
+
+ const head = document.querySelector('head');
+ const style = document.createElement('style');
+ style.append(document.createTextNode(css));
+ style.setAttribute("data-slider-styles", '');
+ head.append(style);
+ }
+
+}
+
+class ProjectTree {
+ constructor({
+ mutatingFrame,
+ controlTarget
+ }) {
+ this.mutatingFrame = mutatingFrame;
+ this.controlTarget = controlTarget;
+ this.fragments = [];
+
+ this.control;
+ this.controlElement;
+
+ this.state = {
+ fragmentVisibility: {
+ _sessionStorageItemName: 'projectTreeFragmentVisibility',
+ initial: 'hide',
+ current: null,
+ }
+ };
+ }
+
+ init() {
+ // console.log('First time call.');
+
+ console.assert(this.mutatingFrame, `mutatingFrame not found on the page`);
+ this._addMutationObserver();
+
+ this._initStateAndStorage();
+
+ // * this.controlTarget may not be present on the page, for example, in the case of static export.
+ // console.assert(this.controlTarget, `controlTarget not found on the page`);
+
+ this._createControl();
+ this._addControl();
+
+ this.updateFragmentsAndControl();
+ }
+
+ getCurrentFragmentVisibilityBool() {
+ return (this.state.fragmentVisibility.current === 'show') ? true : false;
+ }
+
+ updateFragmentsAndControl() {
+ // Update list of fragment elements (files + folders) and toggle visibility
+ const fileFragments = this._getFileFragments();
+ const folderFragments = this._getFoldersWithOnlyFragments();
+
+ // Store both individual file fragments and folders that contain only fragments
+ this.fragments = [...fileFragments, ...folderFragments];
+
+ // Only show number of file fragments (folders are excluded from count)
+ this._updateControl(fileFragments.length);
+ this._updateFragmentsVisibility(this.getCurrentFragmentVisibilityBool());
+ }
+
+ _getFileFragments() {
+ // Find all file elements that are marked as included fragments
+ return [...this.mutatingFrame.querySelectorAll(FRAGMENT_SELECTOR)];
+ }
+
+ _getFoldersWithOnlyFragments() {
+ // Find folders that contain only fragment files and no other files
+ const folders = [...this.mutatingFrame.querySelectorAll(FOLDER_SELECTOR)];
+ return folders.filter(folder => {
+ // Consider only those folders if it contains only fragment files
+ const fragCount = folder.querySelectorAll(FRAGMENT_SELECTOR).length;
+ const fileCount = folder.querySelectorAll(FILE_SELECTOR).length;
+ return fragCount > 0 && fragCount === fileCount;
+ });
+ }
+
+ _getFragments() {
+ let fragments = [...this.mutatingFrame.querySelectorAll(FRAGMENT_SELECTOR)];
+ const folders = this._prepareFragmentsFolders(fragments);
+ return fragments.concat(folders);
+ }
+
+ _prepareFragmentsFolders(fragments) {
+ // Temporary solution.
+ // It is possible to optimize the search to reduce the number of runs.
+
+ const result = [];
+ // .project_tree-folder > .project_tree-folder-content > .project_tree-file === fragment
+ const folders = [...this.mutatingFrame.querySelectorAll(FOLDER_SELECTOR)];
+ folders.forEach(folder => {
+ const frag = folder.querySelectorAll(FRAGMENT_SELECTOR);
+ const file = folder.querySelectorAll(FILE_SELECTOR);
+ if (frag.length === file.length) {
+ result.push(folder);
+ }
+ });
+ return result
+ }
+
+ _updateFragmentsVisibility(bool) {
+ const display = bool ? '' : 'none';
+ this.fragments.forEach(element => {
+ element.style.display = display;
+ })
+ }
+
+ _updateControl(num) {
+ this.control.updateLabelText(`Show ${num} fragment${num > 1 ? 's' : ''} included in other documents in the Project document tree.`)
+
+ if (num) {
+ this._addControl();
+ } else {
+ this._removeControl();
+ }
+ }
+
+ toggleFragmentsVisibility(checked) {
+ this._updateFragmentsVisibility(checked);
+
+ if (checked) {
+ this._updateCurrentState('show', 'fragmentVisibility');
+ this._setSessionStorageItem('show', 'fragmentVisibility');
+ } else {
+ this._updateCurrentState('hide', 'fragmentVisibility');
+ this._setSessionStorageItem('hide', 'fragmentVisibility');
+ }
+ }
+
+ _initStateAndStorage(option = 'fragmentVisibility') {
+ const storage = this._getSessionStorageItem(option);
+
+ if (storage) {
+ this._updateCurrentState(storage);
+ } else {
+ this._updateCurrentState(this.state[option].initial);
+ this._setSessionStorageItem(this.state[option].initial);
+ }
+ }
+
+ _updateCurrentState(value, option = 'fragmentVisibility') {
+ this.state[option].current = value;
+ }
+
+ _setSessionStorageItem(nextState, option = 'fragmentVisibility') {
+ sessionStorage.setItem(this.state[option]._sessionStorageItemName, nextState);
+ }
+
+ _getSessionStorageItem(option = 'fragmentVisibility') {
+ const storage = sessionStorage.getItem(this.state[option]._sessionStorageItemName);
+ return storage;
+ }
+
+ _createControl() {
+ this.control = new Switch(
+ {
+ labelText: `Show fragments`, // * This text will be updated later.
+ dataTestID: 'show-hide-fragments-toggler',
+ size: 0.5,
+ stroke: 0.175,
+ // position: 'absolute',
+ // topPosition: '16px',
+ // leftPosition: 0,
+ // checked: false,
+ checked: this.getCurrentFragmentVisibilityBool(),
+ callback: (checked) => this.toggleFragmentsVisibility(checked),
+ }
+ );
+ this.controlElement = this.control.create();
+ }
+
+ _addControl() {
+ // * this.controlTarget may not be present on the page, for example, in the case of static export.
+ this.controlTarget && this.controlTarget.append(this.controlElement);
+ }
+
+ _removeControl() {
+ this.controlElement.remove();
+ }
+
+ _addMutationObserver() {
+ // console.log('Mutation observer added for', this.mutatingFrame);
+
+ new MutationObserver((mutationsList, observer) => {
+ for (let mutation of mutationsList) {
+ if (mutation.type === 'childList') {
+ // When re-rendering the frame content,
+ // the array of tracked elements should be updated
+ // and their visibility should be set according
+ // to the current settings available in the State.
+ this.updateFragmentsAndControl();
+ }
+ }
+ }).observe(
+ this.mutatingFrame,
+ {
+ childList: true,
+ // subtree: true
+ }
+ );
+ }
+}
+
+window.addEventListener("DOMContentLoaded", function(){
+
+ const controlTarget = document.querySelector(SWITCH_SELECTOR);
+ // * This element may not be present on the page, for example, in the case of static export.
+ // if (!controlTarget) {
+ // console.error(`Selector "${SWITCH_SELECTOR}" not found on the page`);
+ // return;
+ // }
+
+ const mutatingFrame = document.querySelector(FRAME_SELECTOR);
+ if (!mutatingFrame) {
+ console.error(`Selector "${FRAME_SELECTOR}" not found on the page`);
+ return;
+ }
+
+ const projectTree = new ProjectTree({
+ mutatingFrame,
+ controlTarget
+ });
+
+ projectTree.init();
+
+},false);
diff --git a/tests/fuzz/20_L1_Open_Requirements_Tool_202511/assets/requirement-tree.css b/tests/fuzz/20_L1_Open_Requirements_Tool_202511/assets/requirement-tree.css
new file mode 100644
index 0000000..b0aa443
--- /dev/null
+++ b/tests/fuzz/20_L1_Open_Requirements_Tool_202511/assets/requirement-tree.css
@@ -0,0 +1,283 @@
+:root {
+ --requirement-tree-line-width: 1px;
+ --requirement-tree-line-color: var(--color-border);
+ --requirement-tree-margin: var(--tree-gap);
+ --requirement-tree-downward-margin: calc(var(--requirement-tree-margin)*.5);
+ --requirement-tree-downward-string-margin: calc(var(--requirement-tree-downward-margin)*0.25);
+ --requirement-tree-line: var(--requirement-tree-line-width) solid;
+ --requirement-tree-downward-line: var(--requirement-tree-line-color) var(--requirement-tree-line-width) solid;
+ --requirement-tree-arrow-size: calc(var(--requirement-tree-margin)/4);
+ /* var(--color-fg-contrast) */
+ /* var(--color-accent) */
+}
+
+/* requirement-tree */
+
+.requirement-tree {
+ position: relative;
+
+ list-style: none;
+ padding: 0;
+ margin: 0;
+ box-sizing: border-box;
+
+ display: flex;
+ justify-content: flex-start;
+ flex-direction: column;
+ align-content: flex-start;
+
+ /* default aka right direction */
+ align-items: flex-start;
+ margin-left: var(--requirement-tree-margin);
+}
+
+.requirement-tree_right.requirement-tree {
+ align-items: flex-start;
+ margin-right: 0;
+ margin-left: var(--requirement-tree-margin);
+}
+
+.requirement-tree_left.requirement-tree {
+ align-items: flex-end;
+ margin-left: 0;
+ margin-right: var(--requirement-tree-margin);
+}
+
+.requirement-tree_branch {
+ position: relative;
+
+ display: flex;
+ justify-content: center;
+ align-items: flex-start;
+ align-content: stretch;
+ margin-bottom: var(--requirement-tree-margin);
+}
+
+.requirement-tree_left .requirement-tree_branch {
+ flex-direction: row-reverse;
+}
+
+.requirement-tree_branch:last-child {
+ margin-bottom: 0;
+}
+
+.requirement-tree_node {
+ display: flex;
+ flex-direction: column;
+ align-items: stretch;
+
+ /* for width restrictions in deep trace */
+ max-width: var(--card-width);
+}
+
+[data-viewtype="requirements-coverage"] .requirement-tree_node {
+ width: calc(var(--card-width)*0.75);
+}
+
+ /* arrows */
+
+.requirement-tree_right.requirement-tree::before {
+ /* arrow from children, show only in right tree */
+ content: '';
+ position: absolute;
+ width: var(--requirement-tree-arrow-size);
+ height: var(--requirement-tree-arrow-size);
+ top: var(--requirement-tree-margin);
+ left: calc(var(--requirement-tree-margin)*(-1) - var(--requirement-tree-line-width)*0.5);
+ box-sizing: border-box;
+ border-top: var(--requirement-tree-line);
+ border-left: var(--requirement-tree-line);
+ transform-origin: top left;
+ transform: rotate(-45deg);
+ z-index: 2;
+}
+
+.requirement-tree_left .requirement-tree_node::before {
+ /* arrow to parents inside tree */
+ content: '';
+ position: absolute;
+ width: var(--requirement-tree-arrow-size);
+ height: var(--requirement-tree-arrow-size);
+ top: var(--requirement-tree-margin);
+ right: calc(var(--requirement-tree-arrow-size)*(-1));
+ box-sizing: border-box;
+ border-top: var(--requirement-tree-line);
+ border-left: var(--requirement-tree-line);
+ transform-origin: top left;
+ transform: rotate(-45deg);
+ z-index: 2;
+}
+
+/* corner connector to node */
+
+.requirement-tree_branch::before {
+ content: '';
+ position: absolute;
+ width: calc(var(--requirement-tree-margin)*0.5);
+ height: var(--requirement-tree-margin);
+ top: 0;
+ box-sizing: border-box;
+ /* default aka right direction */
+ border-bottom: var(--requirement-tree-line);
+ border-left: var(--requirement-tree-line);
+ left: calc(var(--requirement-tree-margin)*(-1)*0.5);
+}
+
+.requirement-tree_right .requirement-tree_branch::before {
+ right: unset;
+ left: calc(var(--requirement-tree-margin)*(-1)*0.5);
+ border: none;
+ border-bottom: var(--requirement-tree-line);
+ border-left: var(--requirement-tree-line);
+}
+
+.requirement-tree_left .requirement-tree_branch::before {
+ left: unset;
+ right: calc(var(--requirement-tree-margin)*(-1)*0.5);
+ border: none;
+ border-bottom: var(--requirement-tree-line);
+ border-right: var(--requirement-tree-line);
+}
+
+/* horizontal line to top node instead corner */
+
+.requirement-tree_branch:first-child::before {
+ width: var(--requirement-tree-margin);
+ border: none;
+ border-bottom: var(--requirement-tree-line);
+ /* default aka right direction */
+ right: unset;
+ left: calc(var(--requirement-tree-margin)*(-1));
+}
+
+.requirement-tree_right .requirement-tree_branch:first-child::before {
+ right: unset;
+ left: calc(var(--requirement-tree-margin)*(-1));
+}
+
+.requirement-tree_left .requirement-tree_branch:first-child::before {
+ left: unset;
+ right: calc(var(--requirement-tree-margin)*(-1));
+}
+
+/* vertical line */
+
+.requirement-tree_branch::after {
+ content: '';
+ position: absolute;
+ width: calc(var(--requirement-tree-margin)*0.5);
+ top: var(--requirement-tree-margin);
+ bottom: calc(var(--requirement-tree-margin)*(-1));
+ box-sizing: border-box;
+ /* default aka right direction */
+ border: none;
+ border-left: var(--requirement-tree-line);
+ left: calc(var(--requirement-tree-margin)*(-1)*0.5);
+}
+
+.requirement-tree_right .requirement-tree_branch::after {
+ border: none;
+ border-left: var(--requirement-tree-line);
+ right: unset;
+ left: calc(var(--requirement-tree-margin)*(-1)*0.5);
+}
+
+.requirement-tree_left .requirement-tree_branch::after {
+ border: none;
+ border-right: var(--requirement-tree-line);
+ left: unset;
+ right: calc(var(--requirement-tree-margin)*(-1)*0.5);
+}
+
+/* vertical line on last node is not showing */
+.requirement-tree_branch:last-child:after {
+ content: none;
+}
+
+/* downward */
+
+.requirement-tree_downward {
+ list-style: none;
+ padding: 0;
+ margin: 0;
+ margin-left: var(--requirement-tree-downward-margin);
+ box-sizing: border-box;
+
+ font-size: .75rem;
+ line-height: 1.2;
+}
+
+.requirement-tree_downward_node {
+ position: relative;
+ border-left: var(--requirement-tree-downward-line);
+}
+
+.requirement-tree_downward .requirement-tree_downward_node {
+ padding-top: calc(var(--requirement-tree-downward-margin)*0.5);
+}
+
+.requirement-tree_downward .requirement-tree_downward_node:first-child {
+ padding-top: var(--requirement-tree-downward-margin);
+}
+
+.requirement-tree_downward .requirement-tree_downward_node:last-child {
+ border-color: transparent;
+}
+
+.requirement-tree_downward .requirement-tree_downward_node::before {
+ position: absolute;
+ content: '';
+ width: var(--requirement-tree-downward-margin);
+ border-bottom: var(--requirement-tree-downward-line);
+ box-sizing: border-box;
+ top: 0;
+ left: calc(var(--requirement-tree-line-width)*(-1));
+ bottom: calc(100% - var(--requirement-tree-downward-margin)*0.5 - 0.75rem);
+}
+
+.requirement-tree_downward .requirement-tree_downward_node:last-child::before {
+ border-left: var(--requirement-tree-downward-line);
+}
+
+.requirement-tree_downward .requirement-tree_downward_node:first-child::before {
+ bottom: calc(100% - var(--requirement-tree-downward-margin)*1 - 0.75rem);
+}
+
+.requirement-tree_downward_node .requirement-tree_downward_item {
+ position: relative;
+ /* margin-left: calc(var(--requirement-tree-downward-margin) + var(--requirement-tree-downward-string-margin)); */
+ margin-left: calc(var(--requirement-tree-downward-margin) - 0.25rem);
+
+ border-radius: 4px;
+ overflow: clip;
+ border: 1px solid var(--requirement-tree-line-color);
+ background-color: var(--color-bg-main);
+
+ overflow-wrap: break-word;
+}
+
+.requirement-tree_downward_item span,
+.requirement-tree_downward_item a {
+ padding: 4px 6px;
+ display: inline-block;
+ width: 100%;
+ overflow-wrap: break-word;
+}
+
+.requirement-tree_downward_item a {
+ color: var(--color-accent);
+ text-decoration: none;
+}
+
+.requirement-tree_downward_item a:hover {
+ text-decoration: underline;
+}
+
+/* hover */
+
+/* .requirement-tree_node:hover + .requirement-tree::before,
+.requirement-tree_node:hover + .requirement-tree .requirement-tree::before,
+.requirement-tree_node:hover + .requirement-tree .requirement-tree_branch::before,
+.requirement-tree_node:hover + .requirement-tree .requirement-tree_branch::after {
+ border-width: 2px;
+} */
diff --git a/tests/fuzz/20_L1_Open_Requirements_Tool_202511/assets/requirement__temporary.css b/tests/fuzz/20_L1_Open_Requirements_Tool_202511/assets/requirement__temporary.css
new file mode 100644
index 0000000..24122fe
--- /dev/null
+++ b/tests/fuzz/20_L1_Open_Requirements_Tool_202511/assets/requirement__temporary.css
@@ -0,0 +1,138 @@
+/* TODO: should be revised and then moved to a permanent location or removed */
+
+/* requirement__title */
+
+.requirement__title {
+ margin: 0;
+ line-height: 1.6;
+ font-weight: bold;
+}
+
+/* requirement: parent / child / file */
+
+ul.requirement__link {
+ font-size: .85rem;
+ line-height: 1.4;
+ list-style: none;
+ padding: 0;
+}
+
+[data-viewtype="source-file"] ul.requirement__link li {
+ margin-top: 0.5rem;
+}
+
+.requirement__link a,
+.requirement__link li > span {
+ display: inline-block;
+ position: relative;
+ margin-left: 1.5rem;
+ width: calc(100% - 1.5rem);
+ overflow-wrap: break-word;
+}
+
+.requirement__link a::before,
+.requirement__link li > span::before {
+ color: #808080;
+ position: absolute;
+ left: -1.5rem;
+}
+
+.requirement__link a:link,
+.requirement__link a:visited {
+ color: var(--color-fg-contrast);
+ text-decoration: none;
+}
+
+.requirement__link a:hover {
+ /* color: var(--color-fg-accent); */
+ text-decoration: underline;
+}
+
+/* .requirement__link a::before {
+ content: '\2014';
+} */
+
+a.requirement__link-file::before,
+.requirement__link-file::before {
+ content: '>';
+}
+
+a.requirement__link-parent::before {
+ content: '\2190';
+}
+
+a.requirement__link-child::before {
+ content: '\2192';
+}
+
+.requirement__link-external::before {
+ content: '\21D6';
+}
+
+.requirement__parent-uid,
+.requirement__child-uid {
+ position: relative;
+ font-weight: bold;
+}
+
+/* switch (injected by JS) */
+
+.std-switch {
+ display: flex;
+ align-items: center;
+ justify-content: flex-start;
+
+ user-select: none;
+ cursor: pointer;
+}
+
+.std-switch input {
+ opacity: 0;
+ width: 0;
+ height: 0;
+ position: absolute;
+}
+
+.std-switch_slider {
+
+ position: relative;
+ cursor: pointer;
+ background-color: #ccc;
+ -webkit-transition: .4s;
+ transition: .4s;
+
+ display: inline-block;
+ width: 44px;
+ height: 26px;
+ margin-right: 10px;
+
+ border-radius: 22px;
+}
+
+.std-switch_slider::before {
+ position: absolute;
+ content: "";
+ height: 18px;
+ width: 18px;
+ left: 4px;
+ bottom: 4px;
+ background-color: white;
+ -webkit-transition: .4s;
+ transition: .4s;
+
+ border-radius: 50%;
+}
+
+input:checked + .std-switch_slider {
+ background-color: rgb(100, 222, 50);
+}
+
+input:focus + .std-switch_slider {
+ box-shadow: 0 0 1px rgb(100, 222, 50);
+}
+
+input:checked + .std-switch_slider:before {
+ -webkit-transform: translateX(18px);
+ -ms-transform: translateX(18px);
+ transform: translateX(18px);
+}
diff --git a/tests/fuzz/20_L1_Open_Requirements_Tool_202511/assets/resizable_bar.js b/tests/fuzz/20_L1_Open_Requirements_Tool_202511/assets/resizable_bar.js
new file mode 100644
index 0000000..098482c
--- /dev/null
+++ b/tests/fuzz/20_L1_Open_Requirements_Tool_202511/assets/resizable_bar.js
@@ -0,0 +1,602 @@
+// Expected in element:
+// js-resizable_bar="name"
+// data-state="open|closed"
+// data-position="left|right"
+
+class ResizableBar {
+ constructor({
+ barAttribute,
+ barOpenMinWidth,
+ barOpenMaxWidthRatio,
+ // styles
+ barPadding,
+ barPaddingBottom,
+ barClosedWidth,
+ barHandlerWidth,
+ barColorMain,
+ barColorBackground,
+ barColorActive,
+ barColorBorder,
+ barColorScrollbarTrack,
+ barColorScrollbarThumb,
+ }) {
+ this.barAttribute = barAttribute || 'js-resizable_bar';
+ this.barOpenMaxWidthRatio = barOpenMaxWidthRatio || 0.2;
+ this.barOpenMinWidth = barOpenMinWidth || 77;
+ // styles
+ this.barPadding = barPadding || 'calc(var(--base-rhythm, 8px)*2)';
+ this.barPaddingBottom = barPaddingBottom || 'calc(var(--base-rhythm, 8px)*8)';
+ this.barClosedWidth = barClosedWidth || 12;
+ this.barHandlerWidth = barHandlerWidth || 8;
+ this.barColorMain = barColorMain || 'var(--color-fg-main, Black)';
+ this.barColorBackground = barColorBackground || 'var(--color-bg-main, White)';
+ this.barColorActive = barColorActive || 'var(--color-fg-accent, currentColor)';
+ this.barColorBorder = barColorBorder || 'var(--color-border, rgba(0,0,0,0.1))';
+ this.barColorScrollbarTrack = barColorScrollbarTrack || 'var(--scrollbarBG, transparent)';
+ this.barColorScrollbarThumb = barColorScrollbarThumb || 'var(--thumbBG, rgba(0,0,0,.05))';
+
+ // state
+ this.state = {
+ current: {
+ id: null,
+ direction: null, // 1||-1
+ pageX: null
+ }
+ };
+
+ this.initialState = 'open';
+ this.initialWidth = `${this.barOpenMaxWidthRatio * 100}vw`;
+ this.initialStyle = ``;
+
+ // subscribe
+ const _this = this;
+ this._mouseDownHandler = (e) => {_this._onMouseDown(e)};
+ this._mouseMoveHandler = (e) => {_this._onMouseMove(e)};
+ this._mouseUpHandler = (e) => {_this._onMouseUp(e)};
+ this._toggleHandler = (e) => {_this._toggle(e)};
+ }
+
+ init() {
+ this._insertInitialBarStyle();
+ this._insertInitialPreloaderStyle();
+ }
+
+ render() {
+ this._renderBars();
+ this._insertBarStyle();
+ this._insertPreloaderStyle();
+ }
+
+ // render
+
+ _renderBars() {
+ [...document.querySelectorAll(`[${this.barAttribute}]`)]
+ .forEach((bar) => {
+ const id = bar.getAttribute(this.barAttribute);
+ const position = bar.dataset.position;
+ const direction = (bar.dataset.position === 'left') ? 1 : -1;;
+ const state = this._sessionStorageGetItem(id, 'state') || this.initialState;
+ const width = this._sessionStorageGetItem(id, 'width');
+
+ // Read data from element and from Storage
+ // and set to State:
+ this._setState({
+ id: id,
+ element: bar,
+ position: position,
+ direction: direction,
+ state: state,
+ width: width,
+ });
+
+ // Update Bar with data from Storage:
+ this._updateBar(id);
+
+ // Wrap the bar content in the created scrolling element:
+ const wrapper = this._createScrollableWrapper(id);
+ [ ...bar.childNodes ].forEach(child => wrapper.appendChild(child));
+ bar.appendChild(wrapper);
+
+ // Add control elements:
+ bar.append(this._createHandler(id));
+
+ // Add testID:
+ this._addTestID(bar, id, 'bar');
+ });
+ }
+
+ _adjustWidth(width) {
+ let adjustedWidth = width;
+ const max = window.innerWidth * this.barOpenMaxWidthRatio;
+ if(width && width < this.barOpenMinWidth) {
+ adjustedWidth = this.barOpenMinWidth
+ }
+ if(width && width > max) {
+ adjustedWidth = null;
+ }
+ return adjustedWidth;
+ }
+
+ // session storage
+
+ _sessionStorageGet() {
+ return JSON.parse(sessionStorage.getItem('resizableBarStorage'))
+ }
+
+ _sessionStorageSet(obj) {
+ const string = JSON.stringify(obj);
+ sessionStorage.setItem('resizableBarStorage', string)
+ }
+
+ _sessionStorageGetItem(id, item) {
+ const storage = this._sessionStorageGet();
+ const value = (storage && storage[id]) ? storage[id][item] : null;
+ return value;
+ }
+
+ _sessionStorageSetItem(id, item, value) {
+ let storage = this._sessionStorageGet() || {};
+ storage = {
+ ...storage,
+ [id]: {
+ ...storage[id],
+ [item]: value,
+ },
+ };
+ this._sessionStorageSet(storage);
+ }
+
+ // state
+
+ _setState({
+ id,
+ element,
+ state,
+ position,
+ direction,
+ width,
+ }) {
+ this.state[id] = {
+ element: element,
+ state: state,
+ position: position,
+ direction: direction,
+ width: width,
+ };
+ }
+
+ _updateState({
+ id,
+ element,
+ state,
+ position,
+ direction,
+ width,
+ }) {
+ console.assert(id, '_updateState(): ID must be provided');
+ if (!this.state[id]) { this.state[id] = {} }
+ if (element) { this.state[id].element = element; }
+ if (state) { this.state[id].state = state; }
+ if (position) { this.state[id].position = position; }
+ if (direction) { this.state[id].direction = direction; }
+ if (width || width===null) { this.state[id].width = width; }
+ }
+
+ // current
+
+ _updateCurrent(e) {
+ if (e.type == "mousedown") {
+ // When we start a new resize, we update the currents:
+ this.state.current.id = e.target.dataset.content;
+ this.state.current.pageX = e.pageX;
+ this.state.current.startWidth = this.state[this.state.current.id].element.offsetWidth;
+ } else {
+ // e.type == "mouseup"
+ // At the end of the resize:
+ this.state.current.id = null;
+ this.state.current.pageX = null;
+ this.state.current.startWidth = null;
+ }
+ }
+
+ // elements
+
+ _addTestID(element, id, attr) {
+ element.dataset.testid = `${id}-${attr}`;
+ }
+
+ _updateBar(id) {
+ const barState = this.state[id];
+ const bar = this.state[id].element;
+ bar.dataset.position = barState.position;
+ bar.dataset.state = barState.state;
+ this._updateBarWidth(bar, barState.width);
+ }
+
+ _updateBarWidth(bar, width) {
+ // If there is no specific width, set the maximum.
+ // The style tag cannot be left empty to override the preloaded styles
+ // set for each bar with the width taken from the storage
+ // before the page is rendered.
+ bar.style.width = width ? `${width}px` : `${this.barOpenMaxWidthRatio * 100}vw`;
+ }
+
+ _createHandler(id) {
+ const handler = document.createElement('div');
+ handler.setAttribute(`${this.barAttribute}-handler`, '');
+ handler.dataset.content = id;
+ handler.style[this.state[id].position] = 'unset'; // 'left | right'
+
+ const border = document.createElement('div');
+ border.setAttribute(`${this.barAttribute}-border`, '');
+ border.dataset.content = id;
+ border.title = `Resize ${id}`;
+ border.addEventListener('mousedown', this._mouseDownHandler);
+
+ const button = document.createElement('div');
+ button.setAttribute(`${this.barAttribute}-button`, '');
+ button.dataset.content = id;
+ button.title = `Toggle ${id}`;
+ button.addEventListener('mousedown', this._toggleHandler);
+
+ // Add testIDs:
+ this._addTestID(border, id, 'handler-border');
+ this._addTestID(button, id, 'handler-button');
+
+ handler.append(border, button);
+ return handler;
+ }
+
+ _createScrollableWrapper(id, direction = 'y') {
+ const wrapper = document.createElement('div');
+ wrapper.setAttribute(`${this.barAttribute}-scroll`, direction);
+ wrapper.dataset.content = id;
+ return wrapper;
+ }
+
+ // event listeners
+
+ _onMouseDown(e) {
+ // Init resizing
+ if (e.button == 0) {
+ e.preventDefault();
+ this._updateCurrent(e);
+ window.addEventListener('mousemove', this._mouseMoveHandler);
+ window.addEventListener('mouseup', this._mouseUpHandler);
+ }
+ }
+
+ _onMouseMove(e) {
+ // Resizing
+ const currentId = this.state.current.id;
+ const currentX = this.state.current.pageX;
+ const currentStartWidth = this.state.current.startWidth;
+ const currentBar = this.state[currentId].element;
+
+ // todo: _onMouseUp() does not always stop execution of requestAnimationFrame,
+ // and after the correct width is calculated in _adjustWidth (20vw),
+ // the extreme width from this function can be set again (for ex.: 789px).
+ // requestAnimationFrame(() => {
+
+ // currentId exists if a resize has been initiated
+ if (currentId) {
+
+ // Resize
+ // * delta: the distance traveled by the mouse, starting from the initial point
+ const delta = e.pageX - currentX;
+ // * this.state[currentId].direction = 1 || -1
+ // * w: current bar width
+ this.state.current.width = currentStartWidth + this.state[currentId].direction * delta;
+
+ // Rendering the change in width of the bar:
+ // currentBar.style.width = w + 'px';
+ this._updateBarWidth(currentBar, this.state.current.width);
+
+ // Close/Open
+ if (this.state.current.width < this.barOpenMinWidth) {
+ if (this.state[currentId].state == 'open') {
+ this._close(currentId);
+ }
+ } else {
+ if (this.state[currentId].state == 'closed') {
+ this._open(currentId);
+ }
+ }
+ }
+
+ // })
+ }
+
+ _onMouseUp(e) {
+ // Clean up after work
+ window.removeEventListener('mousemove', this._mouseMoveHandler);
+ window.removeEventListener('mouseup', this._mouseUpHandler);
+
+ const currentWidth = this._adjustWidth(this.state.current.width);
+ this._updateState({ id: this.state.current.id, width: currentWidth });
+ this._sessionStorageSetItem(this.state.current.id, 'width', currentWidth); // WRITE DATA TO STORAGE
+ this._updateBar(this.state.current.id);
+ this._updateCurrent(e);
+ }
+
+ _toggle(e) {
+ if (e.button == 0) {
+ const id = e.target.dataset.content;
+ this.state[id].state = this.state[id].state === 'open'
+ ? 'closed'
+ : 'open';
+ this._sessionStorageSetItem(id, 'state', this.state[id].state);
+ this._updateBar(id);
+ }
+ }
+
+ _open(id) {
+ this.state[id].state = 'open';
+ this._sessionStorageSetItem(id, 'state', this.state[id].state);
+ this._updateBar(id);
+ }
+
+ _close(id) {
+ this.state[id].state = 'closed';
+ this._sessionStorageSetItem(id, 'state', this.state[id].state);
+ this._updateBar(id);
+ }
+
+ // styles
+
+ _insertStyle(css, attr) {
+ const style = document.createElement('style');
+ style.setAttribute(`${this.barAttribute}-${attr}`, '');
+ style.textContent = css;
+ document.head.append(style);
+ }
+
+ _insertInitialBarStyle() {
+ const storage = this._sessionStorageGet();
+
+ let initStyle = `[${this.barAttribute}]{width:${this.barOpenMaxWidthRatio * 100}vw}`;
+
+ // Add styles based on data from Storage:
+ for (let id in storage) {
+ const w = (storage[id].state == 'closed') ? this.barClosedWidth : storage[id].width;
+ // If w = null (this is possible if so in the storage),
+ // the base style will be in effect:
+ w && (initStyle += `[${this.barAttribute}="${id}"]{width:${w}px}`);
+ }
+
+ this._insertStyle(initStyle, 'initial-style')
+ }
+
+ _insertBarStyle() {
+ let barStyle = `
+[${this.barAttribute}] {
+ position: relative;
+ height: 100%;
+ max-width: ${this.barOpenMaxWidthRatio * 100}vw;
+}
+
+[${this.barAttribute}]:hover {
+ z-index: 22;
+}
+
+[${this.barAttribute}][data-state="open"] {
+ min-width: ${this.barOpenMinWidth}px;
+ pointer-events: auto;
+}
+[${this.barAttribute}][data-state="closed"] {
+ max-width: ${this.barClosedWidth}px;
+ min-width: ${this.barClosedWidth}px;
+ pointer-events: none;
+ transition: .5s;
+}
+
+[${this.barAttribute}][data-position="left"] {
+ border-left: none;
+}
+[${this.barAttribute}][data-position="right"] {
+ border-right: none;
+}
+
+[${this.barAttribute}-handler] {
+ pointer-events: auto;
+ position: absolute;
+ top: 0;
+ bottom: 0;
+ left: 0;
+ right: 0;
+ z-index: 10;
+ width: ${this.barHandlerWidth}px;
+ color: ${this.barColorActive};
+}
+
+[${this.barAttribute}-border] {
+ pointer-events: auto;
+ position: absolute;
+ top: 0;
+ bottom: 0;
+ left: 0;
+ right: 0;
+ width: ${this.barHandlerWidth}px;
+ background: transparent;
+ transition: .3s;
+ cursor: col-resize;
+}
+
+[${this.barAttribute}][data-state="closed"] [${this.barAttribute}-border] {
+ cursor: e-resize;
+}
+
+[${this.barAttribute}-border]::before {
+ content: '';
+ position: absolute;
+ top: 0;
+ bottom: 0;
+ left: 0;
+ right: 0;
+ width: 1px;
+ background: ${this.barColorBorder};
+ transition: .3s;
+}
+
+[${this.barAttribute}-border]::after {
+ content: '';
+ position: absolute;
+ top: 0;
+ bottom: 0;
+ left: 0;
+ right: 0;
+ width: ${0.5 * this.barHandlerWidth}px;
+ background: transparent;
+ transition: .3s;
+}
+
+[${this.barAttribute}][data-position="left"] [${this.barAttribute}-border]::before {
+ right: 0;
+ left: unset;
+}
+[${this.barAttribute}][data-position="left"] [${this.barAttribute}-border]::after {
+ right: ${-0.25 * this.barHandlerWidth}px;
+ left: unset;
+}
+
+[${this.barAttribute}][data-position="right"] [${this.barAttribute}-border]::before {
+ right: unset;
+ left: 0;
+}
+[${this.barAttribute}][data-position="right"] [${this.barAttribute}-border]::after {
+ right: unset;
+ left: ${-0.25 * this.barHandlerWidth}px;
+}
+
+[${this.barAttribute}-border]:hover::after {
+ background: ${this.barColorActive};
+}
+
+[${this.barAttribute}-button] {
+ cursor: pointer;
+ position: absolute;
+ z-index: 2;
+ left: 0;
+ right: 0;
+ top: ${-1 * this.barHandlerWidth}px;
+ box-sizing: border-box;
+ width: ${2 * this.barHandlerWidth}px;
+ height: ${2 * this.barHandlerWidth}px;
+ font-size: ${1.5 * this.barHandlerWidth}px;
+ font-weight: bold;
+ border-radius: 50%;
+ border-width: 1px;
+ border-style: solid;
+ border-color: ${this.barColorBackground};
+ background: ${this.barColorBackground};
+ color: ${this.barColorActive};
+ transition: .3s;
+}
+
+[data-position="right"] [${this.barAttribute}-button] {
+ right: 0;
+ left: unset;
+}
+[data-position="left"] [${this.barAttribute}-button] {
+ left: 0;
+ right: unset;
+}
+
+[${this.barAttribute}-button]:hover {
+ color: ${this.barColorMain};
+ border-color: ${this.barColorMain};
+}
+
+/* ❮❯ */
+[${this.barAttribute}-button]::after {
+ content: '❮';
+ position: absolute;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ left: 0;
+ right: 0;
+ top: ${-1 * this.barHandlerWidth}px;
+ bottom: ${-1 * this.barHandlerWidth}px;
+}
+[${this.barAttribute}][data-state="open"] [${this.barAttribute}-button]::after,
+[${this.barAttribute}][data-state="open"][data-position="left"] [${this.barAttribute}-button]::after,
+[${this.barAttribute}][data-state="closed"][data-position="right"] [${this.barAttribute}-button]::after {
+ content: '❮';
+}
+[${this.barAttribute}][data-state="closed"] [${this.barAttribute}-button]::after,
+[${this.barAttribute}][data-state="closed"][data-position="left"] [${this.barAttribute}-button]::after,
+[${this.barAttribute}][data-state="open"][data-position="right"] [${this.barAttribute}-button]::after {
+ content: '❯';
+}
+
+[${this.barAttribute}-scroll] {
+ height: 100%;
+ overflow-x: hidden;
+ overflow-y: scroll;
+ /*padding: ${this.barPadding};
+ padding-bottom: ${this.barPaddingBottom};*/
+ scrollbar-color: ${this.barColorScrollbarTrack} ${this.barColorScrollbarTrack};
+}
+[${this.barAttribute}-scroll='y'] {
+ overflow-x: hidden;
+ overflow-y: scroll;
+}
+[${this.barAttribute}-scroll]:hover {
+ scrollbar-color: ${this.barColorScrollbarThumb} ${this.barColorScrollbarTrack};
+}
+[${this.barAttribute}-scroll]::-webkit-scrollbar-thumb {
+ background-color: ${this.barColorScrollbarTrack};
+}
+[${this.barAttribute}-scroll]:hover::-webkit-scrollbar-thumb {
+ background-color: ${this.barColorScrollbarThumb}
+}
+
+[data-state="closed"] [${this.barAttribute}-scroll] {
+ display: none;
+}
+`;
+
+ this._insertStyle(barStyle, 'style');
+ }
+
+ _insertInitialPreloaderStyle() {
+ let style = `
+ aside {
+ /* for a pseudo preloader [js-resizable_bar]::after, affects: layout_tree,layout_toc */
+ position: relative;
+ }
+ [${this.barAttribute}]::after {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ content: '';
+ position: absolute;
+ left: 0; right: 0; top: 0; bottom: 0;
+ z-index: 2;
+ background-color: ${this.barColorBackground};
+ }
+ `;
+
+ this._insertStyle(style, 'initial-preloader-style');
+ }
+
+ _insertPreloaderStyle() {
+ let style = `
+ [${this.barAttribute}]::after {
+ opacity: 0;
+ transition: .3s;
+ pointer-events: none;
+ }
+ `;
+
+ this._insertStyle(style, 'preloader-style');
+ }
+}
+
+const resizableBar = new ResizableBar({});
+resizableBar.init();
+
+window.addEventListener("load", function () {
+ resizableBar.render();
+});
diff --git a/tests/fuzz/20_L1_Open_Requirements_Tool_202511/assets/source_coverage_screen.css b/tests/fuzz/20_L1_Open_Requirements_Tool_202511/assets/source_coverage_screen.css
new file mode 100644
index 0000000..16df13a
--- /dev/null
+++ b/tests/fuzz/20_L1_Open_Requirements_Tool_202511/assets/source_coverage_screen.css
@@ -0,0 +1,283 @@
+.project_coverage {
+ width: 100%;
+ /* font-size: 0.875rem; */
+}
+
+.project_coverage thead {
+ position: sticky;
+ z-index: 1;
+ top: calc(-1 * var(--base-gap)); /* compensate .main top padding when scrolling */
+}
+
+.project_coverage thead th {
+ /* adding a background prevents the th-button background from working */
+ vertical-align: bottom;
+ border-bottom: var(--base-border);
+ font-size: 0.875em;
+}
+
+.project_coverage thead::before {
+ content: '';
+ position: absolute;
+ z-index: -1;
+ left: calc(-1 * var(--base-gap)); /* compensate .main padding to overlap content */
+ right: calc(-1 * var(--base-gap)); /* compensate .main padding to overlap content */
+ top: calc(-1 * var(--base-gap)); /* compensate .main padding to overlap content */
+ bottom: 0;
+ background: var(--color-bg-main);
+}
+
+.project_coverage th,
+.project_coverage td {
+ padding: calc(0.5 * var(--base-rhythm)) var(--base-rhythm);
+ border-right: var(--base-border);
+ position: relative;
+}
+
+.project_coverage td {
+ text-align: right;
+}
+
+.project_coverage th:last-child,
+.project_coverage td:last-child {
+ border-right: none;
+}
+
+.project_coverage tr:first-child th:first-child, /* tr compensate colspan */
+.project_coverage td:first-child {
+ width: auto;
+ text-align: left;
+}
+
+.project_coverage td:not(:first-child) {
+ width: 1px;
+ white-space: nowrap;
+}
+
+.project_coverage tr.project_coverage-file:hover {
+ background: rgba(255,255,255,0.3);
+}
+
+.project_coverage tr.project_coverage-folder td {
+ padding-right: 0;
+}
+
+.project_coverage-folder-title {
+ /* font-weight: bold; */
+ display: flex;
+ align-items: flex-end;
+ column-gap: calc(0.5 * var(--base-rhythm));
+ /* font-size: 0.75em; */
+ line-height: 1;
+ color: #999;
+ padding: calc(0.5 * var(--base-rhythm));
+ position: relative;
+ background: var(--color-bg-secondary);
+}
+
+.project_coverage-file-link {
+ display: flex;
+ /* column-gap: var(--base-rhythm); */
+ padding: calc(0.5 * var(--base-rhythm));
+ border-radius: calc(0.5 * var(--base-rhythm));
+ transition: background .3s;
+ border: 1px solid rgba(255,255,255,0);
+}
+
+.project_coverage-file-icon {}
+
+.project_coverage-file-title {
+ font-size: 1em;
+ font-weight: 500;
+ line-height: 1.2;
+ transition: color .2s;
+ display: flex;
+ column-gap: var(--base-rhythm);
+}
+
+.project_coverage-file-path {
+ font-size: 0.75em;
+ color: var(--color-fg-secondary);
+ overflow: hidden;
+ white-space: nowrap;
+ text-overflow: ellipsis;
+ position: absolute;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ display: none;
+}
+
+.project_coverage-file-details {
+ position: relative;
+ flex-grow: 1;
+}
+
+.project_coverage-file-link:not([href]):hover {
+ /* color: gray; */
+ /* all this file have no links -> they are red */
+}
+
+.project_coverage-file_uncovered .project_coverage-file-link,
+.project_coverage-file_uncovered .project_coverage-file-title {
+ color: var(--color-danger);
+ font-weight: 400 !important;
+}
+
+.project_coverage-file-link[href]:hover .project_coverage-file-icon,
+.project_coverage-file-link[href]:hover .project_coverage-file-title {
+ color: var(--color-fg-accent);
+}
+
+.project_coverage-file-link[href] .project_coverage-file-icon,
+.project_coverage-file-link[href] .project_coverage-file-title {
+ color: var(--color-fg-main);
+}
+
+/* cols */
+
+.project_coverage-col-line {
+ background-color: rgba(255, 155, 0, 0.05) !important;
+}
+
+.project_coverage-col-func {
+ background-color: rgba(175, 0, 255, 0.05) !important;
+}
+
+.sorted_col.project_coverage-col-line,
+th.project_coverage-col-line {
+ background-color: rgba(255, 155, 0, 0.15) !important;
+}
+
+.sorted_col.project_coverage-col-func,
+th.project_coverage-col-func {
+ background-color: rgba(175, 0, 255, 0.15) !important;
+}
+
+/* value_extended */
+
+.value_extended[data-ext]::after {
+content: attr(data-ext);
+margin-left: 2px;
+font-size: 0.85em;
+font-weight: 200;
+}
+
+/* project_coverage-sort_handler */
+
+.project_coverage-sort_handler {
+ cursor: pointer;
+}
+
+.project_coverage-sort_handler::after {
+ content: '○';
+ display: block;
+}
+
+.project_coverage-sort_handler::before {
+ content: '';
+ cursor: pointer;
+ position: absolute;
+ inset: 0;
+ z-index: -1;
+}
+
+.project_coverage-sort_handler:hover {
+ color: var(--color-blue);
+}
+
+.project_coverage-sort_handler:hover::before {
+ border: 3px solid white;
+}
+
+.project_coverage-sort_handler[sorted]::before {
+ border: 3px solid white;
+}
+
+/* ▿ ▵ △ ▽ ▾ ▴ */
+
+.project_coverage-sort_handler:hover::after {
+ /* the first act: desc */
+ content: '▽';
+}
+
+.project_coverage-sort_handler[sorted='asc']::after {
+ content: '▴';
+}
+
+.project_coverage-sort_handler[sorted='dsc']::after {
+ content: '▾';
+}
+
+.project_coverage-sort_handler[sorted='dsc']:hover::after {
+ content: '△';
+}
+
+.project_coverage-sort_handler[sorted='asc']:hover::after {
+ content: '▽';
+}
+
+/* sort_reset */
+
+.project_coverage-sort_reset {
+ display: flex;
+ flex-direction: column;
+ gap: var(--base-padding);
+}
+
+.project_coverage-sort_reset::after {
+ content: ' ';
+ display: block;
+}
+
+/* sorted sort_reset */
+
+.project_coverage.sorted .project_coverage-sort_reset {
+ cursor: pointer;
+}
+
+.project_coverage.sorted .project_coverage-sort_reset::after {
+ content: 'reset sorting';
+ font-weight: 400;
+ text-align: right;
+ color: var(--color-fg-accent);
+}
+
+.project_coverage.sorted .project_coverage-sort_reset::before {
+ content: '';
+ cursor: pointer;
+ position: absolute;
+ inset: 0;
+ z-index: -1;
+}
+
+.project_coverage.sorted .project_coverage-sort_reset:hover::before {
+ background-color: rgb(255 255 255 / 50%);
+}
+
+/* sorted mods */
+
+.project_coverage.sorted .project_coverage-folder,
+.project_coverage.sorted .project_coverage-file-indent {
+ display: none;
+}
+
+.project_coverage.sorted .project_coverage-file-path {
+ display: block;
+}
+
+.project_coverage.sorted .project_coverage-file-details {
+ position: relative;
+ flex-grow: 1;
+ padding: 0 0 var(--base-padding) 0;
+}
+
+/* color */
+
+.color-secondary {
+ color: var(--color-fg-secondary);
+}
+
+.color-uncovered {
+ color: var(--color-danger);
+}
diff --git a/tests/fuzz/20_L1_Open_Requirements_Tool_202511/assets/source_coverage_screen.js b/tests/fuzz/20_L1_Open_Requirements_Tool_202511/assets/source_coverage_screen.js
new file mode 100644
index 0000000..64fbc86
--- /dev/null
+++ b/tests/fuzz/20_L1_Open_Requirements_Tool_202511/assets/source_coverage_screen.js
@@ -0,0 +1,73 @@
+// @relation(SDOC-SRS-35, scope=file)
+
+document.addEventListener("DOMContentLoaded", () => {
+ const table = document.querySelector(".project_coverage");
+ const tbody = table.querySelector("tbody");
+ const originalRows = Array.from(tbody.rows);
+ let sortState = null;
+
+ const handlers = table.querySelectorAll(".project_coverage-sort_handler");
+ const colgroupCols = table.querySelectorAll("colgroup col");
+
+ handlers.forEach((handler) => {
+ handler.addEventListener("click", () => {
+
+ const dataId = handler.getAttribute("data-id");
+ // We expect:
+ // - Each .project_coverage-sort_handler has a unique data-id
+ // - Each | in sortable rows has matching data-id and data-value
+ // - contains matching the same data-id
+
+ console.assert(dataId, "Missing data-id on sort handler.");
+ if (!dataId) return;
+
+ const isSameColumn = sortState && sortState.id === dataId;
+ const asc = isSameColumn ? !sortState.asc : false;
+
+ const rows = Array.from(tbody.rows);
+ const validRows = rows.filter(row =>
+ row.classList.contains("project_coverage-file") &&
+ row.querySelector(`td[data-id="${dataId}"]`)
+ );
+ if (validRows.length === 0) return;
+
+ validRows.sort((a, b) => {
+ const aCell = a.querySelector(`td[data-id="${dataId}"]`);
+ const bCell = b.querySelector(`td[data-id="${dataId}"]`);
+ const aVal = parseFloat(aCell?.dataset.value || '0');
+ const bVal = parseFloat(bCell?.dataset.value || '0');
+ return asc ? aVal - bVal : bVal - aVal;
+ });
+
+ tbody.innerHTML = "";
+ validRows.forEach(row => tbody.appendChild(row));
+ table.classList.add("sorted");
+
+ handlers.forEach(h => h.removeAttribute("sorted"));
+ handler.setAttribute("sorted", asc ? "asc" : "dsc");
+
+ sortState = { id: dataId, asc };
+
+ // Highlight active
+ colgroupCols.forEach(col => col.classList.remove("sorted_col"));
+ const activeCol = table.querySelector(`colgroup col[data-id="${dataId}"]`);
+ if (activeCol) {
+ activeCol.classList.add("sorted_col");
+ } else {
+ console.warn(`No found for data-id="${dataId}"`);
+ }
+ });
+ });
+
+ const resetter = table.querySelector(".project_coverage-sort_reset");
+ if (resetter) {
+ resetter.addEventListener("click", () => {
+ tbody.innerHTML = "";
+ originalRows.forEach(row => tbody.appendChild(row));
+ table.classList.remove("sorted");
+ handlers.forEach(h => h.removeAttribute("sorted"));
+ colgroupCols.forEach(col => col.classList.remove("sorted_col"));
+ sortState = null;
+ });
+ }
+});
diff --git a/tests/fuzz/20_L1_Open_Requirements_Tool_202511/assets/source_file_screen.css b/tests/fuzz/20_L1_Open_Requirements_Tool_202511/assets/source_file_screen.css
new file mode 100644
index 0000000..06a393a
--- /dev/null
+++ b/tests/fuzz/20_L1_Open_Requirements_Tool_202511/assets/source_file_screen.css
@@ -0,0 +1,410 @@
+* {
+ margin: 0;
+ padding: 0;
+}
+
+[data-viewtype="source-file"] {
+ --source-line: 1px solid rgba(0, 0, 0, .05);
+}
+
+[data-viewtype="source-file"] .layout {
+ grid-template-columns:
+ fit-content(var(--base-gap))
+ minmax(222px, 22%) /* replaced: fit-content(20%) */
+ fit-content(20%)
+ minmax(0, 1fr)
+ fit-content(20%)
+ auto;
+ grid-template-areas:
+ "nav header header header header aside"
+ "nav tree bar_left main bar_right aside"
+ "nav footer footer footer footer aside";
+}
+
+/* left panel */
+
+.source-file__aside {
+ display: flex;
+ flex-direction: column;
+ height: 100%;
+}
+
+/* left scrollable panel */
+
+.source-file__refer { /* wrapper */
+ position: relative;
+ height: 100%;
+ overflow-y: hidden;
+}
+
+.source-file__toc {
+ position: relative;
+ height: 100%;
+ overflow-y: scroll;
+ padding: calc(var(--base-padding)*2)
+ calc(var(--base-padding) / 2)
+ calc(var(--base-padding)*4)
+ calc(var(--base-padding) / 1);
+
+ font-size: var(--font-size-sm);
+
+ transition: margin-left .5s;
+ scrollbar-color: transparent var(--scrollbarBG);
+}
+
+.source-file__toc:hover {
+ scrollbar-color: var(--thumbBG) var(--scrollbarBG);
+}
+
+.source-file__toc::-webkit-scrollbar-thumb {
+ background-color: transparent;
+}
+
+.source-file__toc:hover::-webkit-scrollbar-thumb {
+ background-color: var(--thumbBG)
+}
+
+.source-file__toc-range {
+ background-color: var(--color-highlight-secondary);
+ border-radius: var(--base-rhythm);
+ margin-bottom: var(--tree-gap);
+}
+
+.source-file__toc-range-header {
+ padding: var(--base-rhythm);
+}
+
+.source-file__toc-range-node {
+ border-top: 2px solid var(--color-bg-main);
+}
+
+.source-file__toc-node {
+ border-top: 1px solid var(--color-border);
+ margin-bottom: 2rem;
+}
+
+/* SDOC-NODE in SOURCE */
+
+.source-file__requirement {
+ position: relative;
+ padding: var(--base-rhythm) 0;
+ transition: background-color 0.3s ease-in, border-color 0.3s ease-in;
+ font-size: var(--font-size-xsm);
+ display: flex;
+ flex-direction: column;
+ align-items: stretch;
+ gap: 0.25rem;
+}
+
+.source-file__requirement-links {
+ display: flex;
+ flex-direction: column;
+ align-items: stretch;
+ gap: 0.25rem;
+ margin-top: var(--base-rhythm);
+}
+
+.source-file__requirement-info {
+ word-break: break-word;
+}
+
+.source-file__requirement-uid {
+ display: block;
+ position: relative;
+ font-weight: bold;
+ word-break: break-word;
+}
+
+.source-file__requirement details {
+ display: flex;
+ flex-direction: column;
+ align-items: stretch;
+ gap: 0.25rem;
+}
+
+.source-file__requirement summary {
+ list-style: none;
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ cursor: pointer;
+ position: relative;
+ gap: var(--base-rhythm);
+ align-items: flex-start;
+}
+
+.source-file__requirement summary::-webkit-details-marker {
+ display: none;
+}
+
+.source-file__requirement summary::after {
+ content: "➕";
+ user-select: none;
+ padding: calc(var(--base-rhythm) / 2);
+ margin-left: auto;
+ transition: transform 0.2s;
+ font-size: 8px;
+ color: var(--color-link);
+}
+
+.source-file__requirement:hover summary::after {
+ color: var(--color-hover);
+}
+
+.source-file__requirement details[open] summary::after {
+ content: "➖";
+}
+
+.source-file__requirement-header {
+ display: flex;
+ gap: var(--base-rhythm);
+ align-items: flex-start; /* to push action icon to top */
+}
+
+/* requirement_file */
+
+[data-viewtype="source-file"] .requirement_file li {
+ position: relative;
+}
+
+[data-viewtype="source-file"] .requirement_file li > a,
+[data-viewtype="source-file"] .requirement_file li > span {
+ display: inline-block;
+ padding: .15rem .25rem .15rem 0;
+ line-height: 1;
+}
+
+[data-viewtype="source-file"] .current_file_pseudolink {
+ font-weight: bold;
+ color: #808080;
+}
+
+/* CODE */
+
+.source-file__source {
+ /* position: relative; */
+ position: absolute;
+ inset: 0px;
+ left: var(--tree-gap);
+ overflow: auto;
+
+ padding: var(--tree-gap) 0 calc(var(--tree-gap)*10);
+ transition: box-shadow 0.3s ease-in;
+}
+
+.source-file__source .sdoc-table_key_value {
+ /* font-size: var(--font-size-sm); */
+ font-size: 14px;
+ min-width: 100%;
+ margin-bottom: var(--tree-gap);
+}
+
+.source {
+ display: grid;
+ grid-template-columns:
+ minmax(min-content, max-content)
+ minmax(0, 1fr); /* issue#1370 https://css-tricks.com/preventing-a-grid-blowout/ */
+ gap: 0 0;
+ place-items: stretch stretch;
+ transition: transform 0.3s ease-in;
+ position: relative;
+
+ min-width: 100%;
+ width: max-content;
+
+ font-size: 14px;
+ z-index: 1;
+}
+
+.source_highlight {
+ position: absolute;
+ left: 0;
+ right: 0;
+ background-color: var(--color-highlight);
+ z-index: -1;
+ transition: height 0.3s ease-in, top 0.3s ease-in;
+}
+
+/* source__range */
+
+.source__range {
+ grid-column: 1 / -1;
+ display: contents;
+}
+
+.source__range-closer {
+ grid-column: 1 / -1;
+ /* margin-bottom: var(--tree-gap); */
+ margin-bottom: var(--base-padding);
+}
+
+.source__range-closer-label {
+ display: flex;
+ border-radius: 0 0 6px 6px;
+ column-gap: calc(var(--base-rhythm)* 1);
+ background-color: var(--color-highlight-secondary);
+ padding: var(--base-rhythm);
+}
+
+.source__range-closer-label .source__range-definition::before {
+ content: 'End of';
+ display: inline-block;
+ margin-right: 6px;
+}
+
+.focus .source__range:not(.active),
+.focus .source__range-closer:not(.active) {
+ display: none;
+}
+
+.source__range-cell {
+ background-color: var(--color-highlight-secondary);
+}
+
+.source__range-header {
+ grid-column: 1 / -1;
+ background-color: var(--color-highlight-secondary);
+ padding: var(--base-rhythm);
+ margin-top: var(--tree-gap);
+ border-top-left-radius: var(--base-rhythm);
+}
+
+.source__range-button {
+ display: flex;
+ flex-direction: column;
+ align-items: stretch;
+ justify-content: center;
+ height: 100%;
+}
+
+.source__range-banner {
+ padding: 0 1rem 1rem 0;
+}
+
+.source__range.collapsed .source__range-banner {
+ display: none;
+}
+
+ul.source__range-titles-list {
+ margin: var(--base-rhythm);
+ list-style-type: none;
+}
+
+.source__range.collapsed .source__range-titles-list {
+ display: block;
+}
+
+.source__range.expanded .source__range-titles-list {
+ display: none;
+}
+
+.source__range-title-icon {
+ cursor: help;
+}
+
+/* sdoc-node-content */
+
+.source__range-banner sdoc-node-content[node-view="table"] sdoc-node-field-label {
+ background-color: var(--requirement-bg-light-color);
+}
+
+/* source__range-handler */
+
+.source__range-handler {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ cursor: pointer;
+ height: 100%;
+ color: var(--color-link);
+}
+
+.source__range-handler:hover {
+ color: var(--color-hover);
+}
+
+.source__range .source__range-handler .expanded,
+.source__range.expanded .source__range-handler .collapsed {
+ display: none;
+}
+
+.source__range .source__range-handler .collapsed,
+.source__range.expanded .source__range-handler .expanded {
+ display: unset;
+}
+
+/* source__line */
+
+.source__line {
+ grid-column: 1 / -1;
+ display: contents;
+}
+
+.source.coverage .source__line.covered > div {
+ background: rgba(75, 255, 0, 0.2);
+}
+
+.source__line.highlighted > div {
+ background: var(--color-highlight) !important;
+}
+
+/* line-number */
+
+.source__line-number {
+ grid-column: 1 / 2;
+ padding: 0.25rem 1rem 0.25rem 2rem;
+ text-align: right;
+ border-bottom: var(--source-line);
+ color: var(--color-fg-secondary);
+ background: var(--color-bg-contrast);
+ user-select: none;
+ position: relative;
+}
+
+/* line content */
+
+.source__line-content {
+ grid-column: 2 / 3;
+ padding: 0.25rem 1rem 0.25rem .5rem;
+ border-bottom: var(--source-line);
+ border-left: var(--source-line);
+ background: var(--color-bg-contrast);
+}
+
+/* pointers */
+
+.source__range-pointer {
+ display: inline-block;
+ padding-left: calc(var(--base-rhythm)* 1);
+ padding-right: calc(var(--base-rhythm)* 1);
+ border-radius: 6px;
+}
+
+.source__range-pointer.active {
+ background-color: var(--color-highlight) !important;
+ color: var(--color-fg-contrast) !important;
+}
+
+.focus .source__range-pointer.active {
+ outline: solid 3px yellow;
+}
+
+.source__range-pointer .source__range-pointer_description {
+ font-weight: normal;
+ word-break: break-word;
+}
+
+.source__range-definition {
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ max-width: 100%;
+ min-width: 0;
+ display: inline-block;
+}
+
+/* Pygments */
+
+.highlight {
+ background: transparent !important;
+}
diff --git a/tests/fuzz/20_L1_Open_Requirements_Tool_202511/assets/source_file_screen.js b/tests/fuzz/20_L1_Open_Requirements_Tool_202511/assets/source_file_screen.js
new file mode 100644
index 0000000..8e47e20
--- /dev/null
+++ b/tests/fuzz/20_L1_Open_Requirements_Tool_202511/assets/source_file_screen.js
@@ -0,0 +1,642 @@
+// @relation(SDOC-SRS-36, scope=file)
+
+const __log = (topic, ...payload) => {
+ console.log(`%c ${topic} `, 'background:yellow;color:black',
+ ...payload
+ );
+}
+
+class SimpleTabs {
+ constructor(tabsContainer, tabContentSelector = "sdoc-tab-content") {
+ this.tabsContainer = tabsContainer;
+ this.tabContents = document.querySelectorAll(tabContentSelector);
+ this.tabs = tabsContainer.querySelectorAll("sdoc-tab");
+ this._init();
+ }
+
+ _init() {
+ this.tabs.forEach((tab) => {
+ tab.addEventListener("click", () => {
+ this.activateTab(tab.innerText.trim());
+ });
+ });
+
+ // Activate the tab marked as active, or the first one
+ const activeTab = [...this.tabs].find((t) => t.hasAttribute("active")) || this.tabs[0];
+ this.activateTab(activeTab.innerText.trim());
+ }
+
+ activateTab(tabName) {
+ this.tabs.forEach((tab) => {
+ if (tab.innerText.trim() === tabName) {
+ tab.setAttribute("active", "");
+ } else {
+ tab.removeAttribute("active");
+ }
+ });
+
+ this.tabContents.forEach((content) => {
+ if (content.id === tabName) {
+ content.setAttribute("active", "");
+ } else {
+ content.removeAttribute("active");
+ }
+ });
+ }
+}
+
+class Switch {
+ constructor({
+ callback,
+ labelText,
+ checked,
+ componentClass,
+ colorOn,
+ colorOff,
+ size,
+ stroke,
+ units,
+ alignRight,
+ }) {
+ this.colorOn = colorOn || 'rgb(100, 200, 50)';
+ this.colorOff = colorOff || 'rgb(200, 200, 200)';
+ this.labelText = labelText || '';
+ this.checked = checked || false; // todo: replace true/false with strings
+
+ this.componentClass = componentClass || 'std-switch-scc';
+ this.size = size || 0.75;
+ this.stroke = stroke || 0.25;
+ this.units = units || 'rem';
+ this.alignRight = alignRight || true;
+
+ this.callback = callback;
+ }
+
+ create() {
+ const block = document.createElement('div');
+ block.classList.add(this.componentClass);
+ const label = document.createElement('label');
+ label.classList.add(`${this.componentClass}__label`);
+ const input = document.createElement('input');
+ input.classList.add(`${this.componentClass}__input`);
+ input.type = 'checkbox';
+ input.checked = this.checked;
+ const slider = document.createElement('span');
+ slider.classList.add(`${this.componentClass}__slider`);
+ const text = document.createElement('span');
+ text.innerHTML = this.labelText;
+
+ input.addEventListener('change', () => this.callback(input.checked));
+
+ label.append(input, slider, text);
+ block.append(label);
+ this.insertStyle();
+
+ return block;
+ }
+
+ insertStyle() {
+
+ const css = `
+ .${this.componentClass} {
+ display: inline-block;
+ line-height: 0;
+ }
+ .${this.componentClass}__label {
+ display: inline-flex;
+ gap: ${this.size * 0.5}${this.units};
+ font-size: ${this.size * 1.5}${this.units}; /* 0.75rem; */
+ line-height: ${this.size}${this.units};
+ align-items: center;
+ justify-content: flex-start;
+ user-select: none;
+ cursor: pointer;
+ flex-direction: ${this.alignRight ? "row-reverse" : "row"};
+ text-align: ${this.alignRight ? "right" : "left"};
+ }
+ .${this.componentClass}__input {
+ opacity: 0;
+ width: 0;
+ height: 0;
+ position: absolute;
+ }
+ .${this.componentClass}__slider {
+ position: relative;
+ cursor: pointer;
+ background-color: ${this.colorOff};
+ -webkit-transition: .4s;
+ transition: .4s;
+ display: inline-block;
+ width: ${this.size * 2 + this.stroke * 2}${this.units};
+ height: ${this.size + this.stroke * 2}${this.units};
+ border-radius: ${this.size * 0.5 + this.stroke}${this.units};
+ }
+ .${this.componentClass}__slider::before {
+ position: absolute;
+ content: "";
+ height: ${this.size}${this.units};
+ width: ${this.size}${this.units};
+ left: ${this.stroke}${this.units};
+ bottom: ${this.stroke}${this.units};
+ background-color: white;
+ -webkit-transition: .4s;
+ transition: .4s;
+ border-radius: 50%;
+ }
+ input:checked + .${this.componentClass}__slider {
+ background-color: ${this.colorOn};
+ }
+ input:focus + .${this.componentClass}__slider {
+ box-shadow: 0 0 1px ${this.colorOn};
+ }
+ input:checked + .${this.componentClass}__slider::before {
+ -webkit-transform: translateX(${this.size}${this.units});
+ -ms-transform: translateX(${this.size}${this.units});
+ transform: translateX(${this.size}${this.units});
+ }
+ `;
+
+ const head = document.querySelector('head');
+ const style = document.createElement('style');
+ style.append(document.createTextNode(css));
+ style.setAttribute("data-slider-styles", '');
+ head.append(style);
+ }
+
+}
+
+class Dom {
+ constructor({
+ sourceId,
+ sourceContainerId,
+ referContainerId,
+ hashSplitter,
+ strictdocPointerSelector,
+ strictdocRequirementSelector,
+ strictdocRangeBannerSelector,
+ strictdocRangeBannerHeaderSelector,
+ strictdocRangeHandlerSelector,
+ strictdocRangeCloserSelector,
+ strictdocLineSelector,
+ strictdocLineNumberSelector,
+ strictdocLineContentSelector,
+ strictdocLineRangeSelector,
+ strictdocSourceFilterClass,
+ filteredClass,
+ coveredClass,
+ activeClass,
+ collapsedClass,
+ expandedClass,
+ coverageClass,
+ highlightClass,
+ focusClass,
+ }) {
+
+ // CONSTANTS
+ this.sourceId = sourceId || 'source';
+ this.sourceContainerId = sourceContainerId || 'sourceContainer';
+ this.referContainerId = referContainerId || 'referContainer';
+ this.hashSplitter = hashSplitter || '#';
+
+ // STRICTDOC SPECIFIC
+ this.strictdocPointerSelector = strictdocPointerSelector || '.source__range-pointer';
+ this.strictdocRequirementSelector = strictdocRequirementSelector || '.source-file__requirement';
+ this.strictdocRangeBannerSelector = strictdocRangeBannerSelector || '.source__range';
+ this.strictdocRangeBannerHeaderSelector = strictdocRangeBannerHeaderSelector || '.source__range-header';
+ this.strictdocRangeHandlerSelector = strictdocRangeHandlerSelector || '.source__range-handler';
+ this.strictdocRangeCloserSelector = strictdocRangeCloserSelector || '.source__range-closer';
+ this.strictdocLineSelector = strictdocLineSelector || '.source__line';
+ this.strictdocLineNumberSelector = strictdocLineNumberSelector || '.source__line-number';
+ this.strictdocLineContentSelector = strictdocLineContentSelector || '.source__line-content';
+ this.strictdocLineRangeSelector = strictdocLineRangeSelector || '.source__line-ranges';
+ this.strictdocSourceFilterClass = strictdocSourceFilterClass || 'source__filter';
+ this.filteredClass = filteredClass || 'filtered';
+ this.activeClass = activeClass || 'active';
+ this.coveredClass = coveredClass || 'covered';
+ this.coverageClass = coverageClass || 'coverage';
+ this.collapsedClass = collapsedClass || 'collapsed';
+ this.expandedClass = expandedClass || 'expanded';
+ this.highlightClass = highlightClass || 'highlighted';
+ this.focusClass = focusClass || 'focus';
+
+ // elements
+ this.sourceContainer;
+ this.referContainer;
+ this.source;
+ this.lines = {};
+ this.requirements = {};
+ this.ranges = {};
+ this.closers = {};
+
+ // state
+ this.active = {
+ range: null,
+ pointers: [],
+ labels: [],
+ focus: false,
+ };
+ }
+
+ prepare() {
+ this._prepareSourceContainer();
+ this._prepareReferContainer();
+ this._prepareSource();
+
+ this._prepareLines();
+ this._prepareRanges();
+ this._updateLinesWithRanges();
+ this._updateRangesWithRequirements();
+ this._updateRangesWithHandlers();
+ this._updateRangesWithBanners();
+ this._updateRangesWithClosers();
+
+ // console.log('this.lines', this.lines);
+ // console.log('this.ranges', this.ranges);
+ // console.log('this.closers', this.closers);
+ // console.log('this.requirements', this.requirements);
+ // console.log('this.active', this.active);
+ }
+
+ useLocationHash() {
+ const [_, reqId, rangeBegin, rangeEnd] = window.location.hash.split(this.hashSplitter);
+ const rangeAlias = rangeBegin ? this._generateRangeAlias(rangeBegin, rangeEnd) : undefined;
+
+ this.changeActive({
+ rangeBegin,
+ rangeEnd,
+ rangeAlias,
+ pointers: rangeAlias ? this.ranges[rangeAlias].pointers : null,
+ labels: (reqId && rangeAlias) ? this.ranges[rangeAlias][reqId] : null,
+ });
+
+ this.highlightRange();
+ }
+
+ changeActive = ({
+ rangeBegin,
+ rangeEnd,
+ rangeAlias,
+ pointers,
+ labels,
+ }) => {
+
+ // remove old 'active'
+ this.active.pointers?.forEach(pointer => pointer?.classList.remove(this.activeClass));
+ this.active.labels?.forEach(label => label?.classList.remove(this.activeClass));
+ if (this.active.rangeAlias) {
+ this.ranges[this.active.rangeAlias].banner.classList.remove(this.activeClass);
+
+ const closer = this.closers?.[this.active.rangeEnd];
+ console.assert(
+ closer,
+ "Closer must not be null. One known way of getting this error is " +
+ "when a closing function/range marker is missing and not registered " +
+ "with the file traceability info."
+ );
+
+ closer.classList.remove(this.activeClass);
+ }
+
+ // make changes to state
+ this.active.pointers = pointers;
+ this.active.labels = labels;
+ this.active.rangeBegin = rangeBegin;
+ this.active.rangeEnd = rangeEnd;
+ this.active.rangeAlias = rangeAlias;
+
+ // add new 'active'
+ this.active.pointers?.forEach(pointer => pointer.classList.add(this.activeClass));
+ this.active.labels?.forEach(label => label.classList.add(this.activeClass));
+ this.ranges[rangeAlias]?.banner.classList.add(this.activeClass);
+ this.closers[this.active.rangeEnd]?.classList.add(this.activeClass);
+ }
+
+ toggleRangeBannerVisibility(handler) {
+ const banner = handler.closest(this.strictdocRangeBannerSelector);
+
+ if (banner.classList.contains(this.expandedClass)) {
+ banner.classList.remove(this.expandedClass);
+ banner.classList.add(this.collapsedClass);
+ } else {
+ banner.classList.add(this.expandedClass);
+ banner.classList.remove(this.collapsedClass);
+ }
+ }
+
+ toggleCoverageVisibility(toggler) {
+ if (toggler) {
+ this.source.classList.add(this.coverageClass);
+ } else {
+ this.source.classList.remove(this.coverageClass);
+ }
+ }
+
+ highlightRange() {
+ this.scrollToActiveRangeIfNeeded();
+
+ const begin = parseInt(this.active.rangeBegin, 10);
+ const end = parseInt(this.active.rangeEnd, 10);
+
+ for (var key in this.lines) {
+ this.lines[key].line.classList.remove(this.highlightClass);
+ if (key >= begin && key <= end) {
+ this.lines[key].line.classList.add(this.highlightClass);
+ }
+ }
+ }
+
+ scrollToActiveRangeIfNeeded() {
+ // scroll to highlighted, do not scroll to top when unset highlighting:
+ if (this.active.rangeAlias) {
+ const activeRange = this.ranges[this.active.rangeAlias]?.bannerHeader || 0;
+ requestAnimationFrame(() => {
+ this.scrollTo(activeRange);
+ });
+ }
+ }
+
+ scrollTo(element) {
+ const top = element.offsetTop || 0;
+ this.sourceContainer.scrollTo({
+ top: top,
+ behavior: 'smooth',
+ });
+ }
+
+ _prepareSource() {
+ this.source = document.getElementById(this.sourceId);
+ this.source.style.position = 'relative';
+ this.source.style.zIndex = '1';
+ }
+
+ _prepareSourceContainer() {
+ this.sourceContainer = document.getElementById('sourceContainer');
+ }
+
+ _prepareReferContainer() {
+ this.referContainer = document.getElementById('referContainer');
+ }
+
+ _prepareLines() {
+ this.lines = [...document.querySelectorAll(this.strictdocLineSelector)]
+ .reduce((acc, line) => {
+ const lineNumber = line.querySelector(this.strictdocLineNumberSelector);
+ const lineContent = line.querySelector(this.strictdocLineContentSelector);
+ acc[line.dataset.line] = {
+ line: line,
+ lineNumber: lineNumber,
+ lineContent: lineContent,
+ ranges: []
+ };
+ return acc
+ }, {});
+ }
+
+ _getRangePart(hash) {
+ const parts = hash.split(this.hashSplitter);
+ return `${this.hashSplitter}${parts[parts.length - 2]}${this.hashSplitter}${parts[parts.length - 1]}`;
+ };
+
+ _prepareRanges() {
+ [...document.querySelectorAll(this.strictdocPointerSelector)]
+ .map(pointer => {
+ const thisFileOrOther = pointer.dataset.traceabilityFileType;
+ // consider only references to the current file:
+ if (thisFileOrOther === "other_file") {
+ return;
+ }
+
+ const rangeBegin = pointer.dataset.begin;
+ const rangeEnd = pointer.dataset.end;
+ const rangeReq = pointer.dataset.reqid;
+
+ const range = this._generateRangeAlias(rangeBegin, rangeEnd);
+
+ if (!this.ranges[range]) {
+ // add new range
+ this.ranges[range] = {};
+ this.ranges[range].pointers = [];
+
+ this.ranges[range].beginLine = this.lines[rangeBegin].lineNumber;
+ this.ranges[range].endLine = this.lines[rangeEnd].lineNumber;
+ this.ranges[range].begin = rangeBegin;
+ this.ranges[range].end = rangeEnd;
+ }
+
+ // todo pointers?
+ if (rangeReq) {
+
+ // add pointer from code
+ (this.ranges[range][rangeReq] ??= []).push(pointer);
+
+ } else {
+
+ // add pointer from menu
+ this.ranges[range].pointers.push(pointer);
+ }
+
+ pointer.addEventListener("click", (event) => {
+ const targetHash = `#${rangeReq || ""}${this.hashSplitter}${rangeBegin}${this.hashSplitter}${rangeEnd}`;
+ const currentHash = window.location.hash;
+
+ const isSameHash = currentHash === targetHash;
+ // Buttons linked to requirements include an ID in the hash,
+ // while buttons in the source code do not.
+ // Therefore, only the range part of the hash (e.g., #3#10)
+ // should be compared to identify the currently active range.
+ const isSameRange = this._getRangePart(currentHash) === `${this.hashSplitter}${rangeBegin}${this.hashSplitter}${rangeEnd}`;
+
+ const isModifierPressed = event.metaKey || event.ctrlKey;
+
+ const targetBannerHeader = this.ranges[range]?.bannerHeader;
+ const topBefore = targetBannerHeader?.getBoundingClientRect().top;
+
+ // Modifier click
+ if (isModifierPressed) {
+ event.preventDefault(); // cancel opening a new browser tab
+
+ if (isSameRange) {
+ this._toggleFocus();
+ this._compensateSourceContainerScrollPosition(targetBannerHeader, topBefore);
+ } else {
+ // Sets the URL hash to activate a specific range without reloading the page:
+ window.location.hash = targetHash;
+ this.useLocationHash();
+ this._activateFocus();
+ this._compensateSourceContainerScrollPosition(targetBannerHeader, topBefore);
+ }
+ return;
+ }
+
+ // Normal click
+ if (isSameRange) {
+ // active → reset
+ event.preventDefault();
+ // Removes hash from URL without reloading or adding history entry:
+ history.replaceState(null, '', window.location.pathname);
+ this.useLocationHash();
+ this._clearFocus();
+ this._compensateSourceContainerScrollPosition(targetBannerHeader, topBefore);
+ } else {
+ // inactive → just reset the focus,
+ // the basic functionality via URL will work itself out
+ this._clearFocus();
+ this._compensateSourceContainerScrollPosition(targetBannerHeader, topBefore);
+ }
+ });
+
+ });
+ }
+
+ _compensateSourceContainerScrollPosition(element, topBefore) {
+ // Compensates scroll to keep the given element in the same viewport position.
+ // Expects the element and its initial .getBoundingClientRect().top value as input.
+ // Measures element's top offset relative to the viewport before and after DOM changes.
+ // Uses requestAnimationFrame to wait for DOM/layout updates before measuring again.
+ // Calculates delta = after - before, i.e. how much the element moved visually.
+ // Scrolls by that delta to restore the element's original viewport position.
+ requestAnimationFrame(() => {
+ const topAfter = element?.getBoundingClientRect().top;
+ const delta = topAfter - topBefore;
+ this.sourceContainer.scrollBy({ top: delta });
+ });
+ }
+
+ _toggleFocus() {
+ if (this.active.focus) {
+ this.sourceContainer.classList.remove(this.focusClass);
+ this.referContainer.classList.remove(this.focusClass);
+ } else {
+ this.sourceContainer.classList.add(this.focusClass);
+ this.referContainer.classList.add(this.focusClass);
+ }
+ this.active.focus = !this.active.focus;
+ }
+
+ _activateFocus() {
+ if (!this.active.focus) {
+ this.active.focus = true;
+ this.sourceContainer.classList.add(this.focusClass);
+ this.referContainer.classList.add(this.focusClass);
+ }
+ }
+
+ _clearFocus() {
+ if (this.active.focus) {
+ this.active.focus = false;
+ this.sourceContainer.classList.remove(this.focusClass);
+ this.referContainer.classList.remove(this.focusClass);
+ }
+ }
+
+ _updateRangesWithRequirements() {
+ const requirements = [...document.querySelectorAll(this.strictdocRequirementSelector)];
+ requirements.forEach(requirement => {
+
+ const rangeBegin = requirement.dataset.begin;
+ const rangeEnd = requirement.dataset.end;
+ const rangeReq = requirement.dataset.reqid;
+
+ if (rangeEnd && rangeBegin) {
+ const range = this._generateRangeAlias(rangeBegin, rangeEnd);
+ console.assert(this.ranges[range], "The range must be registered:", range);
+
+ (this.ranges[range].requirements ??= {})[rangeReq] = {};
+ this.ranges[range].requirements[rangeReq].begin = rangeBegin;
+ this.ranges[range].requirements[rangeReq].end = rangeEnd;
+ this.ranges[range].requirements[rangeReq].element = requirement;
+ } else {
+ this.requirements[rangeReq] = requirement;
+ }
+
+
+ })
+ }
+
+ _updateRangesWithHandlers() {
+ const handlers = [...document.querySelectorAll(this.strictdocRangeHandlerSelector)];
+ handlers.forEach(handler => {
+
+ const rangeBegin = handler.dataset.begin;
+ const rangeEnd = handler.dataset.end;
+ const range = this._generateRangeAlias(rangeBegin, rangeEnd);
+
+ console.assert(this.ranges[range], "The range must be registered:", range);
+
+ this.ranges[range].handler = handler;
+ handler.addEventListener("click", event => this.toggleRangeBannerVisibility(event.currentTarget));
+ })
+ }
+
+ _updateRangesWithBanners() {
+ const banners = [...document.querySelectorAll(this.strictdocRangeBannerSelector)];
+ banners.forEach(banner => {
+
+ const rangeBegin = banner.dataset.begin;
+ const rangeEnd = banner.dataset.end;
+
+ if (rangeBegin && rangeEnd) {
+ const range = this._generateRangeAlias(rangeBegin, rangeEnd);
+ console.assert(this.ranges[range], "The range must be registered:", range);
+ this.ranges[range].banner = banner;
+ this.ranges[range].bannerHeader = banner.querySelector(this.strictdocRangeBannerHeaderSelector); // 'source__range-header'
+ }
+ })
+ }
+
+ _updateRangesWithClosers() {
+ const closers = [...document.querySelectorAll(this.strictdocRangeCloserSelector)];
+ closers.forEach(closer => {
+
+ const rangeEnd = closer.dataset.end;
+
+ if (rangeEnd) {
+ this.closers[rangeEnd] = closer;
+ }
+ })
+ }
+
+ _updateLinesWithRanges() {
+ Object.entries(this.ranges).forEach(([key, value]) => {
+ const begin = parseInt(value.begin, 10);
+ const end = parseInt(value.end, 10);
+
+ for (let i = begin; i <= end; i++) {
+ (this.lines[i].ranges ??= []).push(key);
+ (this.lines[i].pointers ??= []).push(...value.pointers);
+
+ console.assert(this.lines[i].lineNumber, `The line ${i} must be registered.`);
+ this.lines[i].lineNumber.classList.add(this.strictdocSourceFilterClass);
+ this.lines[i].line.classList.add(this.coveredClass);
+ }
+ });
+ }
+
+ _generateRangeAlias(begin, end) { return `${begin}${this.hashSplitter}${end}` };
+}
+
+const dom = new Dom({});
+
+window.addEventListener("load", function () {
+ dom.prepare();
+ dom.useLocationHash();
+
+ const switcher = new Switch(
+ {
+ labelText: 'Show coverage',
+ size: 0.5,
+ stroke: 0.2,
+ checked: false,
+ callback: (checked) => dom.toggleCoverageVisibility(checked),
+ }
+ );
+ document.getElementById('sourceCodeCoverageSwitch').append(switcher.create());
+
+ const tabsContainer = document.querySelector("sdoc-tabs");
+ if (tabsContainer) {
+ new SimpleTabs(tabsContainer);
+ }
+
+});
+
+window.addEventListener("hashchange", () => dom.useLocationHash());
diff --git a/tests/fuzz/20_L1_Open_Requirements_Tool_202511/assets/stable_uri_forwarder.js b/tests/fuzz/20_L1_Open_Requirements_Tool_202511/assets/stable_uri_forwarder.js
new file mode 100644
index 0000000..fcabf7f
--- /dev/null
+++ b/tests/fuzz/20_L1_Open_Requirements_Tool_202511/assets/stable_uri_forwarder.js
@@ -0,0 +1,99 @@
+// stable_uri_forwarder.js
+//
+// This script is included from the project's index.html page (in static HTML export)
+// It checks for a known MID or UID in the #anchor, and then
+// redirects to the referenced section or node within the project.
+//
+// Example:
+// http://strictdoc.company.com/#SDOC_UG will redirect to
+// http://strictdoc.company.com/strictdoc/docs/strictdoc_01_user_guide.html#SDOC_UG
+//
+// Thanks to this mechanism, it becomes possible to export stable links to
+// nodes/requirements/sections for integration with external tools.
+// The external links remain stable, even if the node/requirement/section is moved
+// within the project.
+
+
+// Resolve the MID / UID to the correct page / anchor using the projectMap.
+function resolveStableUriRedirectUsingProjectMap(anchor) {
+ for (const [page, nodes] of Object.entries(projectMap)) {
+ for (const node of nodes) {
+ if (node['_LINK'].toLowerCase() === anchor.toLowerCase()) {
+ window.location.replace(page + "#" + node['_LINK']);
+ return;
+ }
+
+ const nodeHasUID = 'UID' in node && typeof node['UID'] === 'string';
+ if (nodeHasUID && node['UID'].toLowerCase() === anchor.toLowerCase()) {
+ window.location.replace(page + "#" + node['_LINK']);
+ return;
+ }
+
+ const nodeHasMID = 'MID' in node && typeof node['MID'] === 'string';
+ if (nodeHasMID && node['MID'].toLowerCase() === anchor.toLowerCase()) {
+ window.location.replace(page + "#" + node['_LINK']);
+ return;
+ }
+ }
+ }
+}
+
+// Dynamically load the projectMap an resolve MID / UID.
+function loadProjectMapAndResolveStableUriRedirect(anchor) {
+
+ // ProjectMap is loaded, no need to load it again.
+ if (typeof projectMap !== 'undefined') {
+ resolveStableUriRedirectUsingProjectMap(anchor);
+ return;
+ }
+
+ // Get script URL and derive from it the url of project_map.js
+ const scriptUrl = new URL(document.getElementById("stable_uri_forwarder").src, window.location
+ .href)
+ const projectMapUrl = new URL('project_map.js', scriptUrl).href;
+
+ // Dynamically load project map and resolve
+ const script = document.createElement("script");
+ script.src = projectMapUrl;
+ script.onload = () => resolveStableUriRedirectUsingProjectMap(anchor);
+ script.onerror = () => {
+ console.error(`Failed to load project map from ${projectMapUrl}`);
+ };
+ document.head.appendChild(script);
+}
+
+function processStableUriRedirect(anchor) {
+ const exportType = document.querySelector('meta[name="strictdoc-export-type"]')?.content;
+
+ if (exportType === 'webserver') {
+ // For the web server, we let the main_router.py dynamically forward UID to node.
+ window.location.replace("/UID/" + anchor);
+ } else if (exportType === 'static') {
+ // For static exports, we use the project_map.js.
+ loadProjectMapAndResolveStableUriRedirect(anchor)
+ }
+}
+
+
+// In case an anchor is present at content load time.
+document.addEventListener("DOMContentLoaded", () => {
+ const anchorParam = new URLSearchParams(window.location.search).get("a");
+ if (anchorParam) {
+ processStableUriRedirect(anchorParam)
+ return
+ }
+
+ // for legacy link support
+ const anchorHash = window.location.hash.substring(1);
+ if (anchorHash) {
+ processStableUriRedirect(anchorHash)
+ }
+});
+
+// In case an anchor is added manually afterwards (eases testing).
+window.addEventListener("hashchange", () => {
+ const anchor = window.location.hash.substring(1);
+ if (anchor) {
+ processStableUriRedirect(anchor)
+ }
+});
diff --git a/tests/fuzz/20_L1_Open_Requirements_Tool_202511/assets/stimulus_umd.min.js b/tests/fuzz/20_L1_Open_Requirements_Tool_202511/assets/stimulus_umd.min.js
new file mode 100644
index 0000000..0df2936
--- /dev/null
+++ b/tests/fuzz/20_L1_Open_Requirements_Tool_202511/assets/stimulus_umd.min.js
@@ -0,0 +1,5 @@
+!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).Stimulus={})}(this,function(e){"use strict";class K{constructor(e,t,r){this.eventTarget=e,this.eventName=t,this.eventOptions=r,this.unorderedBindings=new Set}connect(){this.eventTarget.addEventListener(this.eventName,this,this.eventOptions)}disconnect(){this.eventTarget.removeEventListener(this.eventName,this,this.eventOptions)}bindingConnected(e){this.unorderedBindings.add(e)}bindingDisconnected(e){this.unorderedBindings.delete(e)}handleEvent(e){var t=function(t){{if("immediatePropagationStopped"in t)return t;{let e=t.stopImmediatePropagation;return Object.assign(t,{immediatePropagationStopped:!1,stopImmediatePropagation(){this.immediatePropagationStopped=!0,e.call(this)}})}}}(e);for(const r of this.bindings){if(t.immediatePropagationStopped)break;r.handleEvent(t)}}hasBindings(){return 0{e=e.index,t=t.index;return ee.connect()))}stop(){this.started&&(this.started=!1,this.eventListeners.forEach(e=>e.disconnect()))}get eventListeners(){return Array.from(this.eventListenerMaps.values()).reduce((e,t)=>e.concat(Array.from(t.values())),[])}bindingConnected(e){this.fetchEventListenerForBinding(e).bindingConnected(e)}bindingDisconnected(e,t=!1){this.fetchEventListenerForBinding(e).bindingDisconnected(e),t&&this.clearEventListenersForBinding(e)}handleError(e,t,r={}){this.application.handleError(e,"Error "+t,r)}clearEventListenersForBinding(e){var t=this.fetchEventListenerForBinding(e);t.hasBindings()||(t.disconnect(),this.removeMappedEventListenerFor(e))}removeMappedEventListenerFor(e){var{eventTarget:e,eventName:t,eventOptions:r}=e,s=this.fetchEventListenerMapForEventTarget(e),t=this.cacheKey(t,r);s.delete(t),0==s.size&&this.eventListenerMaps.delete(e)}fetchEventListenerForBinding(e){var{eventTarget:e,eventName:t,eventOptions:r}=e;return this.fetchEventListener(e,t,r)}fetchEventListener(e,t,r){var s=this.fetchEventListenerMapForEventTarget(e),i=this.cacheKey(t,r);let n=s.get(i);return n||(n=this.createEventListener(e,t,r),s.set(i,n)),n}createEventListener(e,t,r){e=new K(e,t,r);return this.started&&e.connect(),e}fetchEventListenerMapForEventTarget(e){let t=this.eventListenerMaps.get(e);return t||(t=new Map,this.eventListenerMaps.set(e,t)),t}cacheKey(e,t){const r=[e];return Object.keys(t).sort().forEach(e=>{r.push((t[e]?"":"!")+e)}),r.join(":")}}const j={stop({event:e,value:t}){return t&&e.stopPropagation(),!0},prevent({event:e,value:t}){return t&&e.preventDefault(),!0},self({event:e,value:t,element:r}){return!t||r===e.target}},$=/^(?:(?:([^.]+?)\+)?(.+?)(?:\.(.+?))?(?:@(window|document))?->)?(.+?)(?:#([^:]+?))(?::(.+))?$/;function U(e){var t,e=e.trim().match($)||[];let r=e[2],s=e[3];return s&&!["keydown","keyup","keypress"].includes(r)&&(r+="."+s,s=""),{eventTarget:"window"==(t=e[4])?window:"document"==t?document:void 0,eventName:r,eventOptions:e[7]?e[7].split(":").reduce((e,t)=>Object.assign(e,{[t.replace(/^!/,"")]:!/^!/.test(t)}),{}):{},identifier:e[5],methodName:e[6],keyFilter:e[1]||s}}function a(e){return e.replace(/(?:[_-])([a-z0-9])/g,(e,t)=>t.toUpperCase())}function s(e){return a(e.replace(/--/g,"-").replace(/__/g,"_"))}function l(e){return e.charAt(0).toUpperCase()+e.slice(1)}function h(e){return e.replace(/([A-Z])/g,(e,t)=>"-"+t.toLowerCase())}function c(e){return null!=e}function u(e,t){return Object.prototype.hasOwnProperty.call(e,t)}const o=["meta","ctrl","alt","shift"];class P{constructor(e,t,r,s){this.element=e,this.index=t,this.eventTarget=r.eventTarget||e,this.eventName=r.eventName||function(e){var t=e.tagName.toLowerCase();if(t in i)return i[t](e)}(e)||n("missing event name"),this.eventOptions=r.eventOptions||{},this.identifier=r.identifier||n("missing identifier"),this.methodName=r.methodName||n("missing method name"),this.keyFilter=r.keyFilter||"",this.schema=s}static forToken(e,t){return new this(e.element,e.index,U(e.content),t)}toString(){var e=this.keyFilter?"."+this.keyFilter:"",t=this.eventTargetName?"@"+this.eventTargetName:"";return this.eventName+e+t+`->${this.identifier}#`+this.methodName}shouldIgnoreKeyboardEvent(e){var t;return!!this.keyFilter&&(t=this.keyFilter.split("+"),!!this.keyFilterDissatisfied(e,t)||!!(t=t.filter(e=>!o.includes(e))[0])&&(u(this.keyMappings,t)||n("contains unknown key filter: "+this.keyFilter),this.keyMappings[t].toLowerCase()!==e.key.toLowerCase()))}shouldIgnoreMouseEvent(e){var t;return!!this.keyFilter&&(t=[this.keyFilter],!!this.keyFilterDissatisfied(e,t))}get params(){var e,t,r={},s=new RegExp(`^data-${this.identifier}-(.+)-param$`,"i");for({name:e,value:t}of Array.from(this.element.attributes)){var i=e.match(s),i=i&&i[1];i&&(r[a(i)]=function(t){try{return JSON.parse(t)}catch(e){return t}}(t))}return r}get eventTargetName(){return(e=this.eventTarget)==window?"window":e==document?"document":void 0;var e}get keyMappings(){return this.schema.keyMappings}keyFilterDissatisfied(e,t){var[r,s,i,n]=o.map(e=>t.includes(e));return e.metaKey!==r||e.ctrlKey!==s||e.altKey!==i||e.shiftKey!==n}}const i={a:()=>"click",button:()=>"click",form:()=>"submit",details:()=>"toggle",input:e=>"submit"==e.getAttribute("type")?"click":"input",select:()=>"change",textarea:()=>"input"};function n(e){throw new Error(e)}class R{constructor(e,t){this.context=e,this.action=t}get index(){return this.action.index}get eventTarget(){return this.action.eventTarget}get eventOptions(){return this.action.eventOptions}get identifier(){return this.context.identifier}handleEvent(e){var t=this.prepareActionEvent(e);this.willBeInvokedByEvent(e)&&this.applyEventModifiers(t)&&this.invokeWithEvent(t)}get eventName(){return this.action.eventName}get method(){var e=this.controller[this.methodName];if("function"==typeof e)return e;throw new Error(`Action "${this.action}" references undefined method "${this.methodName}"`)}applyEventModifiers(e){var t,r,s,i=this.action.element,n=this.context.application.actionDescriptorFilters,o=this.context.controller;let a=!0;for([t,r]of Object.entries(this.eventOptions))t in n&&(s=n[t],a=a&&s({name:t,value:r,event:e,element:i,controller:o}));return a}prepareActionEvent(e){return Object.assign(e,{params:this.action.params})}invokeWithEvent(t){var{target:r,currentTarget:s}=t;try{this.method.call(this.controller,t),this.context.logDebugActivity(this.methodName,{event:t,target:r,currentTarget:s,action:this.methodName})}catch(e){var{identifier:r,controller:s,element:i,index:n}=this;this.context.handleError(e,`invoking action "${this.action}"`,{identifier:r,controller:s,element:i,index:n,event:t})}}willBeInvokedByEvent(e){var t=e.target;return!(e instanceof KeyboardEvent&&this.action.shouldIgnoreKeyboardEvent(e)||e instanceof MouseEvent&&this.action.shouldIgnoreMouseEvent(e))&&(this.element===t||(t instanceof Element&&this.element.contains(t)?this.scope.containsElement(t):this.scope.containsElement(this.action.element)))}get controller(){return this.context.controller}get methodName(){return this.action.methodName}get element(){return this.scope.element}get scope(){return this.context.scope}}class d{constructor(e,t){this.mutationObserverInit={attributes:!0,childList:!0,subtree:!0},this.element=e,this.started=!1,this.delegate=t,this.elements=new Set,this.mutationObserver=new MutationObserver(e=>this.processMutations(e))}start(){this.started||(this.started=!0,this.mutationObserver.observe(this.element,this.mutationObserverInit),this.refresh())}pause(e){this.started&&(this.mutationObserver.disconnect(),this.started=!1),e(),this.started||(this.mutationObserver.observe(this.element,this.mutationObserverInit),this.started=!0)}stop(){this.started&&(this.mutationObserver.takeRecords(),this.mutationObserver.disconnect(),this.started=!1)}refresh(){if(this.started){var e=new Set(this.matchElementsInTree());for(const t of Array.from(this.elements))e.has(t)||this.removeElement(t);for(const r of Array.from(e))this.addElement(r)}}processMutations(e){if(this.started)for(const t of e)this.processMutation(t)}processMutation(e){"attributes"==e.type?this.processAttributeChange(e.target,e.attributeName):"childList"==e.type&&(this.processRemovedNodes(e.removedNodes),this.processAddedNodes(e.addedNodes))}processAttributeChange(e,t){this.elements.has(e)?this.delegate.elementAttributeChanged&&this.matchElement(e)?this.delegate.elementAttributeChanged(e,t):this.removeElement(e):this.matchElement(e)&&this.addElement(e)}processRemovedNodes(e){for(const r of Array.from(e)){var t=this.elementFromNode(r);t&&this.processTree(t,this.removeElement)}}processAddedNodes(e){for(const r of Array.from(e)){var t=this.elementFromNode(r);t&&this.elementIsActive(t)&&this.processTree(t,this.addElement)}}matchElement(e){return this.delegate.matchElement(e)}matchElementsInTree(e=this.element){return this.delegate.matchElementsInTree(e)}processTree(e,t){for(const r of this.matchElementsInTree(e))t.call(this,r)}elementFromNode(e){if(e.nodeType==Node.ELEMENT_NODE)return e}elementIsActive(e){return e.isConnected==this.element.isConnected&&this.element.contains(e)}addElement(e){this.elements.has(e)||this.elementIsActive(e)&&(this.elements.add(e),this.delegate.elementMatched)&&this.delegate.elementMatched(e)}removeElement(e){this.elements.has(e)&&(this.elements.delete(e),this.delegate.elementUnmatched)&&this.delegate.elementUnmatched(e)}}class m{constructor(e,t,r){this.attributeName=t,this.delegate=r,this.elementObserver=new d(e,this)}get element(){return this.elementObserver.element}get selector(){return`[${this.attributeName}]`}start(){this.elementObserver.start()}pause(e){this.elementObserver.pause(e)}stop(){this.elementObserver.stop()}refresh(){this.elementObserver.refresh()}get started(){return this.elementObserver.started}matchElement(e){return e.hasAttribute(this.attributeName)}matchElementsInTree(e){var t=this.matchElement(e)?[e]:[],e=Array.from(e.querySelectorAll(this.selector));return t.concat(e)}elementMatched(e){this.delegate.elementMatchedAttribute&&this.delegate.elementMatchedAttribute(e,this.attributeName)}elementUnmatched(e){this.delegate.elementUnmatchedAttribute&&this.delegate.elementUnmatchedAttribute(e,this.attributeName)}elementAttributeChanged(e,t){this.delegate.elementAttributeValueChanged&&this.attributeName==t&&this.delegate.elementAttributeValueChanged(e,t)}}function r(e,t,r){p(e,t).add(r)}function g(e,t,r){p(e,t).delete(r),f(e,t)}function p(e,t){let r=e.get(t);return r||(r=new Set,e.set(t,r)),r}function f(e,t){var r=e.get(t);null!=r&&0==r.size&&e.delete(t)}class v{constructor(){this.valuesByKey=new Map}get keys(){return Array.from(this.valuesByKey.keys())}get values(){return Array.from(this.valuesByKey.values()).reduce((e,t)=>e.concat(Array.from(t)),[])}get size(){return Array.from(this.valuesByKey.values()).reduce((e,t)=>e+t.size,0)}add(e,t){r(this.valuesByKey,e,t)}delete(e,t){g(this.valuesByKey,e,t)}has(e,t){e=this.valuesByKey.get(e);return null!=e&&e.has(t)}hasKey(e){return this.valuesByKey.has(e)}hasValue(t){return Array.from(this.valuesByKey.values()).some(e=>e.has(t))}getValuesForKey(e){e=this.valuesByKey.get(e);return e?Array.from(e):[]}getKeysForValue(t){return Array.from(this.valuesByKey).filter(([,e])=>e.has(t)).map(([e])=>e)}}class z extends v{constructor(){super(),this.keysByValue=new Map}get values(){return Array.from(this.keysByValue.keys())}add(e,t){super.add(e,t),r(this.keysByValue,t,e)}delete(e,t){super.delete(e,t),g(this.keysByValue,t,e)}hasValue(e){return this.keysByValue.has(e)}getKeysForValue(e){e=this.keysByValue.get(e);return e?Array.from(e):[]}}class b{constructor(e,t,r,s){this._selector=t,this.details=s,this.elementObserver=new d(e,this),this.delegate=r,this.matchesByElement=new v}get started(){return this.elementObserver.started}get selector(){return this._selector}set selector(e){this._selector=e,this.refresh()}start(){this.elementObserver.start()}pause(e){this.elementObserver.pause(e)}stop(){this.elementObserver.stop()}refresh(){this.elementObserver.refresh()}get element(){return this.elementObserver.element}matchElement(e){var t=this.selector;return!!t&&(t=e.matches(t),this.delegate.selectorMatchElement?t&&this.delegate.selectorMatchElement(e,this.details):t)}matchElementsInTree(e){var t,r=this.selector;return r?(t=this.matchElement(e)?[e]:[],e=Array.from(e.querySelectorAll(r)).filter(e=>this.matchElement(e)),t.concat(e)):[]}elementMatched(e){var t=this.selector;t&&this.selectorMatched(e,t)}elementUnmatched(e){for(const t of this.matchesByElement.getKeysForValue(e))this.selectorUnmatched(e,t)}elementAttributeChanged(e,t){var r,s,i=this.selector;i&&(r=this.matchElement(e),s=this.matchesByElement.has(i,e),r&&!s?this.selectorMatched(e,i):!r&&s&&this.selectorUnmatched(e,i))}selectorMatched(e,t){this.delegate.selectorMatched(e,t,this.details),this.matchesByElement.add(t,e)}selectorUnmatched(e,t){this.delegate.selectorUnmatched(e,t,this.details),this.matchesByElement.delete(t,e)}}class y{constructor(e,t){this.element=e,this.delegate=t,this.started=!1,this.stringMap=new Map,this.mutationObserver=new MutationObserver(e=>this.processMutations(e))}start(){this.started||(this.started=!0,this.mutationObserver.observe(this.element,{attributes:!0,attributeOldValue:!0}),this.refresh())}stop(){this.started&&(this.mutationObserver.takeRecords(),this.mutationObserver.disconnect(),this.started=!1)}refresh(){if(this.started)for(const e of this.knownAttributeNames)this.refreshAttribute(e,null)}processMutations(e){if(this.started)for(const t of e)this.processMutation(t)}processMutation(e){var t=e.attributeName;t&&this.refreshAttribute(t,e.oldValue)}refreshAttribute(e,t){var r=this.delegate.getStringMapKeyForAttribute(e);if(null!=r){this.stringMap.has(e)||this.stringMapKeyAdded(r,e);var s=this.element.getAttribute(e);if(this.stringMap.get(e)!=s&&this.stringMapValueChanged(s,r,t),null==s){const t=this.stringMap.get(e);this.stringMap.delete(e),t&&this.stringMapKeyRemoved(r,e,t)}else this.stringMap.set(e,s)}}stringMapKeyAdded(e,t){this.delegate.stringMapKeyAdded&&this.delegate.stringMapKeyAdded(e,t)}stringMapValueChanged(e,t,r){this.delegate.stringMapValueChanged&&this.delegate.stringMapValueChanged(e,t,r)}stringMapKeyRemoved(e,t,r){this.delegate.stringMapKeyRemoved&&this.delegate.stringMapKeyRemoved(e,t,r)}get knownAttributeNames(){return Array.from(new Set(this.currentAttributeNames.concat(this.recordedAttributeNames)))}get currentAttributeNames(){return Array.from(this.element.attributes).map(e=>e.name)}get recordedAttributeNames(){return Array.from(this.stringMap.keys())}}class O{constructor(e,t,r){this.attributeObserver=new m(e,t,this),this.delegate=r,this.tokensByElement=new v}get started(){return this.attributeObserver.started}start(){this.attributeObserver.start()}pause(e){this.attributeObserver.pause(e)}stop(){this.attributeObserver.stop()}refresh(){this.attributeObserver.refresh()}get element(){return this.attributeObserver.element}get attributeName(){return this.attributeObserver.attributeName}elementMatchedAttribute(e){this.tokensMatched(this.readTokensForElement(e))}elementAttributeValueChanged(e){var[e,t]=this.refreshTokensForElement(e);this.tokensUnmatched(e),this.tokensMatched(t)}elementUnmatchedAttribute(e){this.tokensUnmatched(this.tokensByElement.getValuesForKey(e))}tokensMatched(e){e.forEach(e=>this.tokenMatched(e))}tokensUnmatched(e){e.forEach(e=>this.tokenUnmatched(e))}tokenMatched(e){this.delegate.tokenMatched(e),this.tokensByElement.add(e.element,e)}tokenUnmatched(e){this.delegate.tokenUnmatched(e),this.tokensByElement.delete(e.element,e)}refreshTokensForElement(e){var r,s,t=this.tokensByElement.getValuesForKey(e),e=this.readTokensForElement(e),i=(r=t,s=e,i=Math.max(r.length,s.length),Array.from({length:i},(e,t)=>[r[t],s[t]]).findIndex(([e,t])=>{return t=t,!((e=e)&&t&&e.index==t.index&&e.content==t.content)}));return-1==i?[[],[]]:[t.slice(i),e.slice(i)]}readTokensForElement(e){var r,s,t=this.attributeName,i=e.getAttribute(t)||"";return r=e,s=t,i.trim().split(/\s+/).filter(e=>e.length).map((e,t)=>({element:r,attributeName:s,content:e,index:t}))}}class A{constructor(e,t,r){this.tokenListObserver=new O(e,t,this),this.delegate=r,this.parseResultsByToken=new WeakMap,this.valuesByTokenByElement=new WeakMap}get started(){return this.tokenListObserver.started}start(){this.tokenListObserver.start()}stop(){this.tokenListObserver.stop()}refresh(){this.tokenListObserver.refresh()}get element(){return this.tokenListObserver.element}get attributeName(){return this.tokenListObserver.attributeName}tokenMatched(e){var t=e.element,r=this.fetchParseResultForToken(e).value;r&&(this.fetchValuesByTokenForElement(t).set(e,r),this.delegate.elementMatchedValue(t,r))}tokenUnmatched(e){var t=e.element,r=this.fetchParseResultForToken(e).value;r&&(this.fetchValuesByTokenForElement(t).delete(e),this.delegate.elementUnmatchedValue(t,r))}fetchParseResultForToken(e){let t=this.parseResultsByToken.get(e);return t||(t=this.parseToken(e),this.parseResultsByToken.set(e,t)),t}fetchValuesByTokenForElement(e){let t=this.valuesByTokenByElement.get(e);return t||(t=new Map,this.valuesByTokenByElement.set(e,t)),t}parseToken(e){try{return{value:this.delegate.parseValueForToken(e)}}catch(e){return{error:e}}}}class _{constructor(e,t){this.context=e,this.delegate=t,this.bindingsByAction=new Map}start(){this.valueListObserver||(this.valueListObserver=new A(this.element,this.actionAttribute,this),this.valueListObserver.start())}stop(){this.valueListObserver&&(this.valueListObserver.stop(),delete this.valueListObserver,this.disconnectAllActions())}get element(){return this.context.element}get identifier(){return this.context.identifier}get actionAttribute(){return this.schema.actionAttribute}get schema(){return this.context.schema}get bindings(){return Array.from(this.bindingsByAction.values())}connectAction(e){var t=new R(this.context,e);this.bindingsByAction.set(e,t),this.delegate.bindingConnected(t)}disconnectAction(e){var t=this.bindingsByAction.get(e);t&&(this.bindingsByAction.delete(e),this.delegate.bindingDisconnected(t))}disconnectAllActions(){this.bindings.forEach(e=>this.delegate.bindingDisconnected(e,!0)),this.bindingsByAction.clear()}parseValueForToken(e){e=P.forToken(e,this.schema);if(e.identifier==this.identifier)return e}elementMatchedValue(e,t){this.connectAction(t)}elementUnmatchedValue(e,t){this.disconnectAction(t)}}class q{constructor(e,t){this.context=e,this.receiver=t,this.stringMapObserver=new y(this.element,this),this.valueDescriptorMap=this.controller.valueDescriptorMap}start(){this.stringMapObserver.start(),this.invokeChangedCallbacksForDefaultValues()}stop(){this.stringMapObserver.stop()}get element(){return this.context.element}get controller(){return this.context.controller}getStringMapKeyForAttribute(e){if(e in this.valueDescriptorMap)return this.valueDescriptorMap[e].name}stringMapKeyAdded(e,t){t=this.valueDescriptorMap[t];this.hasValue(e)||this.invokeChangedCallback(e,t.writer(this.receiver[e]),t.writer(t.defaultValue))}stringMapValueChanged(e,t,r){var s=this.valueDescriptorNameMap[t];null!==e&&(null===r&&(r=s.writer(s.defaultValue)),this.invokeChangedCallback(t,e,r))}stringMapKeyRemoved(e,t,r){var s=this.valueDescriptorNameMap[e];this.hasValue(e)?this.invokeChangedCallback(e,s.writer(this.receiver[e]),r):this.invokeChangedCallback(e,s.writer(s.defaultValue),r)}invokeChangedCallbacksForDefaultValues(){for(var{key:e,name:t,defaultValue:r,writer:s}of this.valueDescriptors)null==r||this.controller.data.has(e)||this.invokeChangedCallback(t,s(r),void 0)}invokeChangedCallback(t,r,s){var i=this.receiver[t+"Changed"];if("function"==typeof i){t=this.valueDescriptorNameMap[t];try{var n=t.reader(r);let e=s;s&&(e=t.reader(s)),i.call(this.receiver,n,e)}catch(e){throw e instanceof TypeError&&(e.message=`Stimulus Value "${this.context.identifier}.${t.name}" - `+e.message),e}}}get valueDescriptors(){let t=this.valueDescriptorMap;return Object.keys(t).map(e=>t[e])}get valueDescriptorNameMap(){const t={};return Object.keys(this.valueDescriptorMap).forEach(e=>{e=this.valueDescriptorMap[e];t[e.name]=e}),t}hasValue(e){e="has"+l(this.valueDescriptorNameMap[e].name);return this.receiver[e]}}class W{constructor(e,t){this.context=e,this.delegate=t,this.targetsByName=new v}start(){this.tokenListObserver||(this.tokenListObserver=new O(this.element,this.attributeName,this),this.tokenListObserver.start())}stop(){this.tokenListObserver&&(this.disconnectAllTargets(),this.tokenListObserver.stop(),delete this.tokenListObserver)}tokenMatched({element:e,content:t}){this.scope.containsElement(e)&&this.connectTarget(e,t)}tokenUnmatched({element:e,content:t}){this.disconnectTarget(e,t)}connectTarget(e,t){var r;this.targetsByName.has(t,e)||(this.targetsByName.add(t,e),null!=(r=this.tokenListObserver)&&r.pause(()=>this.delegate.targetConnected(e,t)))}disconnectTarget(e,t){var r;this.targetsByName.has(t,e)&&(this.targetsByName.delete(t,e),null!=(r=this.tokenListObserver))&&r.pause(()=>this.delegate.targetDisconnected(e,t))}disconnectAllTargets(){for(const e of this.targetsByName.keys)for(const t of this.targetsByName.getValuesForKey(e))this.disconnectTarget(t,e)}get attributeName(){return`data-${this.context.identifier}-target`}get element(){return this.context.element}get scope(){return this.context.scope}}function E(e,r){e=t(e);return Array.from(e.reduce((t,e)=>(function(e,t){e=e[t];return Array.isArray(e)?e:[]}(e,r).forEach(e=>t.add(e)),t),new Set))}function J(e,r){return t(e).reduce((e,t)=>(e.push(...function(e,t){const r=e[t];return r?Object.keys(r).map(e=>[e,r[e]]):[]}(t,r)),e),[])}function t(e){for(var t=[];e;)t.push(e),e=Object.getPrototypeOf(e);return t.reverse()}class H{constructor(e,t){this.started=!1,this.context=e,this.delegate=t,this.outletsByName=new v,this.outletElementsByName=new v,this.selectorObserverMap=new Map,this.attributeObserverMap=new Map}start(){this.started||(this.outletDefinitions.forEach(e=>{this.setupSelectorObserverForOutlet(e),this.setupAttributeObserverForOutlet(e)}),this.started=!0,this.dependentContexts.forEach(e=>e.refresh()))}refresh(){this.selectorObserverMap.forEach(e=>e.refresh()),this.attributeObserverMap.forEach(e=>e.refresh())}stop(){this.started&&(this.started=!1,this.disconnectAllOutlets(),this.stopSelectorObservers(),this.stopAttributeObservers())}stopSelectorObservers(){0e.stop()),this.selectorObserverMap.clear())}stopAttributeObservers(){0e.stop()),this.attributeObserverMap.clear())}selectorMatched(e,t,{outletName:r}){var s=this.getOutlet(e,r);s&&this.connectOutlet(s,e,r)}selectorUnmatched(e,t,{outletName:r}){var s=this.getOutletFromMap(e,r);s&&this.disconnectOutlet(s,e,r)}selectorMatchElement(e,{outletName:t}){var r=this.selector(t),s=this.hasOutlet(e,t),t=e.matches(`[${this.schema.controllerAttribute}~=${t}]`);return!!r&&s&&t&&e.matches(r)}elementMatchedAttribute(e,t){t=this.getOutletNameFromOutletAttributeName(t);t&&this.updateSelectorObserverForOutlet(t)}elementAttributeValueChanged(e,t){t=this.getOutletNameFromOutletAttributeName(t);t&&this.updateSelectorObserverForOutlet(t)}elementUnmatchedAttribute(e,t){t=this.getOutletNameFromOutletAttributeName(t);t&&this.updateSelectorObserverForOutlet(t)}connectOutlet(e,t,r){var s;this.outletElementsByName.has(r,t)||(this.outletsByName.add(r,e),this.outletElementsByName.add(r,t),null!=(s=this.selectorObserverMap.get(r))&&s.pause(()=>this.delegate.outletConnected(e,t,r)))}disconnectOutlet(e,t,r){var s;this.outletElementsByName.has(r,t)&&(this.outletsByName.delete(r,e),this.outletElementsByName.delete(r,t),null!=(s=this.selectorObserverMap.get(r)))&&s.pause(()=>this.delegate.outletDisconnected(e,t,r))}disconnectAllOutlets(){for(const e of this.outletElementsByName.keys)for(const t of this.outletElementsByName.getValuesForKey(e))for(const r of this.outletsByName.getValuesForKey(e))this.disconnectOutlet(r,t,e)}updateSelectorObserverForOutlet(e){var t=this.selectorObserverMap.get(e);t&&(t.selector=this.selector(e))}setupSelectorObserverForOutlet(e){var t=this.selector(e),t=new b(document.body,t,this,{outletName:e});this.selectorObserverMap.set(e,t),t.start()}setupAttributeObserverForOutlet(e){var t=this.attributeNameForOutletName(e),t=new m(this.scope.element,t,this);this.attributeObserverMap.set(e,t),t.start()}selector(e){return this.scope.outlets.getSelectorForOutletName(e)}attributeNameForOutletName(e){return this.scope.schema.outletAttributeForScope(this.identifier,e)}getOutletNameFromOutletAttributeName(t){return this.outletDefinitions.find(e=>this.attributeNameForOutletName(e)===t)}get outletDependencies(){const r=new v;return this.router.modules.forEach(t=>{E(t.definition.controllerConstructor,"outlets").forEach(e=>r.add(e,t.identifier))}),r}get outletDefinitions(){return this.outletDependencies.getKeysForValue(this.identifier)}get dependentControllerIdentifiers(){return this.outletDependencies.getValuesForKey(this.identifier)}get dependentContexts(){const t=this.dependentControllerIdentifiers;return this.router.contexts.filter(e=>t.includes(e.identifier))}hasOutlet(e,t){return!!this.getOutlet(e,t)||!!this.getOutletFromMap(e,t)}getOutlet(e,t){return this.application.getControllerForElementAndIdentifier(e,t)}getOutletFromMap(t,e){return this.outletsByName.getValuesForKey(e).find(e=>e.element===t)}get scope(){return this.context.scope}get schema(){return this.context.schema}get identifier(){return this.context.identifier}get application(){return this.context.application}get router(){return this.application.router}}class M{constructor(e,t){this.logDebugActivity=(e,t={})=>{var{identifier:r,controller:s,element:i}=this;t=Object.assign({identifier:r,controller:s,element:i},t),this.application.logDebugActivity(this.identifier,e,t)},this.module=e,this.scope=t,this.controller=new e.controllerConstructor(this),this.bindingObserver=new _(this,this.dispatcher),this.valueObserver=new q(this,this.controller),this.targetObserver=new W(this,this),this.outletObserver=new H(this,this);try{this.controller.initialize(),this.logDebugActivity("initialize")}catch(e){this.handleError(e,"initializing controller")}}connect(){this.bindingObserver.start(),this.valueObserver.start(),this.targetObserver.start(),this.outletObserver.start();try{this.controller.connect(),this.logDebugActivity("connect")}catch(e){this.handleError(e,"connecting controller")}}refresh(){this.outletObserver.refresh()}disconnect(){try{this.controller.disconnect(),this.logDebugActivity("disconnect")}catch(e){this.handleError(e,"disconnecting controller")}this.outletObserver.stop(),this.targetObserver.stop(),this.valueObserver.stop(),this.bindingObserver.stop()}get application(){return this.module.application}get identifier(){return this.module.identifier}get schema(){return this.application.schema}get dispatcher(){return this.application.dispatcher}get element(){return this.scope.element}get parentElement(){return this.element.parentElement}handleError(e,t,r={}){var{identifier:s,controller:i,element:n}=this;r=Object.assign({identifier:s,controller:i,element:n},r),this.application.handleError(e,"Error "+t,r)}targetConnected(e,t){this.invokeControllerMethod(t+"TargetConnected",e)}targetDisconnected(e,t){this.invokeControllerMethod(t+"TargetDisconnected",e)}outletConnected(e,t,r){this.invokeControllerMethod(s(r)+"OutletConnected",e,t)}outletDisconnected(e,t,r){this.invokeControllerMethod(s(r)+"OutletDisconnected",e,t)}invokeControllerMethod(e,...t){var r=this.controller;"function"==typeof r[e]&&r[e](...t)}}function Z(e){return r=E(n=e=e,"blessings"),r=r.reduce((e,t)=>{var r=t(n);for(const i in r){var s=e[i]||{};e[i]=Object.assign(s,r[i])}return e},{}),t=Q(e),e=function(s,i){return G(i).reduce((e,t)=>{var r=function(e,t,r){var e=Object.getOwnPropertyDescriptor(e,r),s=e&&"value"in e;if(!s)return s=Object.getOwnPropertyDescriptor(t,r).value,e&&(s.get=e.get||s.get,s.set=e.set||s.set),s}(s,i,t);return r&&Object.assign(e,{[t]:r}),e},{})}(e.prototype,r),Object.defineProperties(t.prototype,e),t;var t,n,r}const G="function"==typeof Object.getOwnPropertySymbols?e=>[...Object.getOwnPropertyNames(e),...Object.getOwnPropertySymbols(e)]:Object.getOwnPropertyNames,Q=(()=>{function e(e){function t(){return Reflect.construct(e,arguments,new.target)}return t.prototype=Object.create(e.prototype,{constructor:{value:t}}),Reflect.setPrototypeOf(t,e),t}try{return(t=e(function(){this.a.call(this)})).prototype.a=function(){},new t,e}catch(e){return e=>class extends e{}}var t})();class X{constructor(e,t){this.application=e,this.definition={identifier:t.identifier,controllerConstructor:Z(t.controllerConstructor)},this.contextsByScope=new WeakMap,this.connectedContexts=new Set}get identifier(){return this.definition.identifier}get controllerConstructor(){return this.definition.controllerConstructor}get contexts(){return Array.from(this.connectedContexts)}connectContextForScope(e){e=this.fetchContextForScope(e);this.connectedContexts.add(e),e.connect()}disconnectContextForScope(e){e=this.contextsByScope.get(e);e&&(this.connectedContexts.delete(e),e.disconnect())}fetchContextForScope(e){let t=this.contextsByScope.get(e);return t||(t=new M(this,e),this.contextsByScope.set(e,t)),t}}class Y{constructor(e){this.scope=e}has(e){return this.data.has(this.getDataKey(e))}get(e){return this.getAll(e)[0]}getAll(e){return(this.data.get(this.getDataKey(e))||"").match(/[^\s]+/g)||[]}getAttributeName(e){return this.data.getAttributeNameForKey(this.getDataKey(e))}getDataKey(e){return e+"-class"}get data(){return this.scope.data}}class ee{constructor(e){this.scope=e}get element(){return this.scope.element}get identifier(){return this.scope.identifier}get(e){e=this.getAttributeNameForKey(e);return this.element.getAttribute(e)}set(e,t){var r=this.getAttributeNameForKey(e);return this.element.setAttribute(r,t),this.get(e)}has(e){e=this.getAttributeNameForKey(e);return this.element.hasAttribute(e)}delete(e){return!!this.has(e)&&(e=this.getAttributeNameForKey(e),this.element.removeAttribute(e),!0)}getAttributeNameForKey(e){return`data-${this.identifier}-`+h(e)}}class te{constructor(e){this.warnedKeysByObject=new WeakMap,this.logger=e}warn(e,t,r){let s=this.warnedKeysByObject.get(e);s||(s=new Set,this.warnedKeysByObject.set(e,s)),s.has(t)||(s.add(t),this.logger.warn(r,e))}}function w(e,t){return`[${e}~="${t}"]`}class re{constructor(e){this.scope=e}get element(){return this.scope.element}get identifier(){return this.scope.identifier}get schema(){return this.scope.schema}has(e){return null!=this.find(e)}find(...e){return e.reduce((e,t)=>e||this.findTarget(t)||this.findLegacyTarget(t),void 0)}findAll(...e){return e.reduce((e,t)=>[...e,...this.findAllTargets(t),...this.findAllLegacyTargets(t)],[])}findTarget(e){e=this.getSelectorForTargetName(e);return this.scope.findElement(e)}findAllTargets(e){e=this.getSelectorForTargetName(e);return this.scope.findAllElements(e)}getSelectorForTargetName(e){return w(this.schema.targetAttributeForScope(this.identifier),e)}findLegacyTarget(e){var t=this.getLegacySelectorForTargetName(e);return this.deprecate(this.scope.findElement(t),e)}findAllLegacyTargets(t){var e=this.getLegacySelectorForTargetName(t);return this.scope.findAllElements(e).map(e=>this.deprecate(e,t))}getLegacySelectorForTargetName(e){e=this.identifier+"."+e;return w(this.schema.targetAttribute,e)}deprecate(e,t){var r,s,i;return e&&(r=this.identifier,s=this.schema.targetAttribute,i=this.schema.targetAttributeForScope(r),this.guide.warn(e,"target:"+t,`Please replace ${s}="${r}.${t}" with ${i}="${t}". `+`The ${s} attribute is deprecated and will be removed in a future version of Stimulus.`)),e}get guide(){return this.scope.guide}}class se{constructor(e,t){this.scope=e,this.controllerElement=t}get element(){return this.scope.element}get identifier(){return this.scope.identifier}get schema(){return this.scope.schema}has(e){return null!=this.find(e)}find(...e){return e.reduce((e,t)=>e||this.findOutlet(t),void 0)}findAll(...e){return e.reduce((e,t)=>[...e,...this.findAllOutlets(t)],[])}getSelectorForOutletName(e){e=this.schema.outletAttributeForScope(this.identifier,e);return this.controllerElement.getAttribute(e)}findOutlet(e){var t=this.getSelectorForOutletName(e);if(t)return this.findElement(t,e)}findAllOutlets(e){var t=this.getSelectorForOutletName(e);return t?this.findAllElements(t,e):[]}findElement(t,r){return this.scope.queryElements(t).filter(e=>this.matchesElement(e,t,r))[0]}findAllElements(t,r){return this.scope.queryElements(t).filter(e=>this.matchesElement(e,t,r))}matchesElement(e,t,r){var s=e.getAttribute(this.scope.schema.controllerAttribute)||"";return e.matches(t)&&s.split(" ").includes(r)}}class k{constructor(e,t,r,s){this.targets=new re(this),this.classes=new Y(this),this.data=new ee(this),this.containsElement=e=>e.closest(this.controllerSelector)===this.element,this.schema=e,this.element=t,this.identifier=r,this.guide=new te(s),this.outlets=new se(this.documentScope,t)}findElement(e){return this.element.matches(e)?this.element:this.queryElements(e).find(this.containsElement)}findAllElements(e){return[...this.element.matches(e)?[this.element]:[],...this.queryElements(e).filter(this.containsElement)]}queryElements(e){return Array.from(this.element.querySelectorAll(e))}get controllerSelector(){return w(this.schema.controllerAttribute,this.identifier)}get isDocumentScope(){return this.element===document.documentElement}get documentScope(){return this.isDocumentScope?this:new k(this.schema,document.documentElement,this.identifier,this.guide.logger)}}class ie{constructor(e,t,r){this.element=e,this.schema=t,this.delegate=r,this.valueListObserver=new A(this.element,this.controllerAttribute,this),this.scopesByIdentifierByElement=new WeakMap,this.scopeReferenceCounts=new WeakMap}start(){this.valueListObserver.start()}stop(){this.valueListObserver.stop()}get controllerAttribute(){return this.schema.controllerAttribute}parseValueForToken(e){var{element:e,content:t}=e;return this.parseValueForElementAndIdentifier(e,t)}parseValueForElementAndIdentifier(e,t){var r=this.fetchScopesByIdentifierForElement(e);let s=r.get(t);return s||(s=this.delegate.createScopeForElementAndIdentifier(e,t),r.set(t,s)),s}elementMatchedValue(e,t){var r=(this.scopeReferenceCounts.get(t)||0)+1;this.scopeReferenceCounts.set(t,r),1==r&&this.delegate.scopeConnected(t)}elementUnmatchedValue(e,t){var r=this.scopeReferenceCounts.get(t);r&&(this.scopeReferenceCounts.set(t,r-1),1==r)&&this.delegate.scopeDisconnected(t)}fetchScopesByIdentifierForElement(e){let t=this.scopesByIdentifierByElement.get(e);return t||(t=new Map,this.scopesByIdentifierByElement.set(e,t)),t}}class ne{constructor(e){this.application=e,this.scopeObserver=new ie(this.element,this.schema,this),this.scopesByIdentifier=new v,this.modulesByIdentifier=new Map}get element(){return this.application.element}get schema(){return this.application.schema}get logger(){return this.application.logger}get controllerAttribute(){return this.schema.controllerAttribute}get modules(){return Array.from(this.modulesByIdentifier.values())}get contexts(){return this.modules.reduce((e,t)=>e.concat(t.contexts),[])}start(){this.scopeObserver.start()}stop(){this.scopeObserver.stop()}loadDefinition(e){this.unloadIdentifier(e.identifier);var t=new X(this.application,e),t=(this.connectModule(t),e.controllerConstructor.afterLoad);t&&t.call(e.controllerConstructor,e.identifier,this.application)}unloadIdentifier(e){e=this.modulesByIdentifier.get(e);e&&this.disconnectModule(e)}getContextForElementAndIdentifier(t,e){e=this.modulesByIdentifier.get(e);if(e)return e.contexts.find(e=>e.element==t)}proposeToConnectScopeForElementAndIdentifier(e,t){var r=this.scopeObserver.parseValueForElementAndIdentifier(e,t);r?this.scopeObserver.elementMatchedValue(r.element,r):console.error(`Couldn't find or create scope for identifier: "${t}" and element:`,e)}handleError(e,t,r){this.application.handleError(e,t,r)}createScopeForElementAndIdentifier(e,t){return new k(this.schema,e,t,this.logger)}scopeConnected(e){this.scopesByIdentifier.add(e.identifier,e);var t=this.modulesByIdentifier.get(e.identifier);t&&t.connectContextForScope(e)}scopeDisconnected(e){this.scopesByIdentifier.delete(e.identifier,e);var t=this.modulesByIdentifier.get(e.identifier);t&&t.disconnectContextForScope(e)}connectModule(t){this.modulesByIdentifier.set(t.identifier,t),this.scopesByIdentifier.getValuesForKey(t.identifier).forEach(e=>t.connectContextForScope(e))}disconnectModule(t){this.modulesByIdentifier.delete(t.identifier),this.scopesByIdentifier.getValuesForKey(t.identifier).forEach(e=>t.disconnectContextForScope(e))}}const N={controllerAttribute:"data-controller",actionAttribute:"data-action",targetAttribute:"data-target",targetAttributeForScope:e=>`data-${e}-target`,outletAttributeForScope:(e,t)=>`data-${e}-${t}-outlet`,keyMappings:Object.assign(Object.assign({enter:"Enter",tab:"Tab",esc:"Escape",space:" ",up:"ArrowUp",down:"ArrowDown",left:"ArrowLeft",right:"ArrowRight",home:"Home",end:"End",page_up:"PageUp",page_down:"PageDown"},F("abcdefghijklmnopqrstuvwxyz".split("").map(e=>[e,e]))),F("0123456789".split("").map(e=>[e,e])))};function F(e){return e.reduce((e,[t,r])=>Object.assign(Object.assign({},e),{[t]:r}),{})}class oe{constructor(e=document.documentElement,t=N){this.logger=console,this.debug=!1,this.logDebugActivity=(e,t,r={})=>{this.debug&&this.logFormattedMessage(e,t,r)},this.element=e,this.schema=t,this.dispatcher=new I(this),this.router=new ne(this),this.actionDescriptorFilters=Object.assign({},j)}static start(e,t){e=new this(e,t);return e.start(),e}async start(){await new Promise(e=>{"loading"==document.readyState?document.addEventListener("DOMContentLoaded",()=>e()):e()}),this.logDebugActivity("application","starting"),this.dispatcher.start(),this.router.start(),this.logDebugActivity("application","start")}stop(){this.logDebugActivity("application","stopping"),this.dispatcher.stop(),this.router.stop(),this.logDebugActivity("application","stop")}register(e,t){this.load({identifier:e,controllerConstructor:t})}registerActionOption(e,t){this.actionDescriptorFilters[e]=t}load(e,...t){(Array.isArray(e)?e:[e,...t]).forEach(e=>{e.controllerConstructor.shouldLoad&&this.router.loadDefinition(e)})}unload(e,...t){(Array.isArray(e)?e:[e,...t]).forEach(e=>this.router.unloadIdentifier(e))}get controllers(){return this.router.contexts.map(e=>e.controller)}getControllerForElementAndIdentifier(e,t){e=this.router.getContextForElementAndIdentifier(e,t);return e?e.controller:null}handleError(e,t,r){this.logger.error(`%s
+
+%o
+
+%o`,t,e,r),null!=(r=window.onerror)&&r.call(window,t,"",0,0,e)}logFormattedMessage(e,t,r={}){r=Object.assign({application:this},r),this.logger.groupCollapsed(e+" #"+t),this.logger.log("details:",Object.assign({},r)),this.logger.groupEnd()}}function B(e,t,r){return e.application.getControllerForElementAndIdentifier(t,r)}function C(e,t,r){var s=B(e,t,r);return s||(e.application.router.proposeToConnectScopeForElementAndIdentifier(t,r),B(e,t,r))||void 0}function T([s,n],o){{let{token:e,typeDefinition:i}=o={controller:o,token:s,typeDefinition:n},t=h(e)+"-value",r=function(e){var{controller:e,token:t,typeDefinition:r}=e,s={controller:e,token:t,typeObject:r},s=function(e){var{controller:t,token:r,typeObject:s}=e,i=c(s.type),n=c(s.default),o=i&&n,a=i&&!n,i=!i&&n,n=S(s.type),e=x(e.typeObject.default);if(a)return n;if(i)return e;if(n===e)return o?n:void 0;throw new Error(`The specified default value for the Stimulus Value "${t?t+"."+r:r}" must match the defined type "${n}". The provided default value of "${s.default}" is of type "${e}".`)}(s),i=x(r),n=S(r),s=s||i||n;if(s)return s;i=e?e+"."+r:t;throw new Error(`Unknown value type "${i}" for "${t}" value`)}(o);return{type:r,key:t,name:a(t),get defaultValue(){var e=i;if(t=S(e))return D[t];var t=u(e,"default"),r=u(e,"type"),s=e;if(t)return s.default;if(r){t=s.type,r=S(t);if(r)return D[r]}return e},get hasCustomDefaultValue(){return void 0!==x(i)},reader:ae[r],writer:L[r]||L.default}}}function S(e){switch(e){case Array:return"array";case Boolean:return"boolean";case Number:return"number";case Object:return"object";case String:return"string"}}function x(e){switch(typeof e){case"boolean":return"boolean";case"number":return"number";case"string":return"string"}return Array.isArray(e)?"array":"[object Object]"===Object.prototype.toString.call(e)?"object":void 0}const D={get array(){return[]},boolean:!1,number:0,get object(){return{}},string:""},ae={array(e){var t=JSON.parse(e);if(Array.isArray(t))return t;throw new TypeError(`expected value of type "array" but instead got value "${e}" of type "${x(t)}"`)},boolean(e){return!("0"==e||"false"==String(e).toLowerCase())},number(e){return Number(e.replace(/_/g,""))},object(e){var t=JSON.parse(e);if(null===t||"object"!=typeof t||Array.isArray(t))throw new TypeError(`expected value of type "object" but instead got value "${e}" of type "${x(t)}"`);return t},string(e){return e}},L={default:function(e){return""+e},array:le,object:le};function le(e){return JSON.stringify(e)}class V{constructor(e){this.context=e}static get shouldLoad(){return!0}static afterLoad(e,t){}get application(){return this.context.application}get scope(){return this.context.scope}get element(){return this.scope.element}get identifier(){return this.scope.identifier}get targets(){return this.scope.targets}get outlets(){return this.scope.outlets}get classes(){return this.scope.classes}get data(){return this.scope.data}initialize(){}connect(){}disconnect(){}dispatch(e,{target:t=this.element,detail:r={},prefix:s=this.identifier,bubbles:i=!0,cancelable:n=!0}={}){s=new CustomEvent(s?s+":"+e:e,{detail:r,bubbles:i,cancelable:n});return t.dispatchEvent(s),s}}V.blessings=[function(e){return E(e,"classes").reduce((e,t)=>{return Object.assign(e,{[(r=t)+"Class"]:{get(){var e=this.classes;if(e.has(r))return e.get(r);throw e=e.getAttributeName(r),new Error(`Missing attribute "${e}"`)}},[r+"Classes"]:{get(){return this.classes.getAll(r)}},[`has${l(r)}Class`]:{get(){return this.classes.has(r)}}});var r},{})},function(e){return E(e,"targets").reduce((e,t)=>{return Object.assign(e,{[(r=t)+"Target"]:{get(){var e=this.targets.find(r);if(e)return e;throw new Error(`Missing target element "${r}" for "${this.identifier}" controller`)}},[r+"Targets"]:{get(){return this.targets.findAll(r)}},[`has${l(r)}Target`]:{get(){return this.targets.has(r)}}});var r},{})},function(e){const t=J(e,"values");return t.reduce((e,t)=>Object.assign(e,function(e,t){let r=T(e,t),{key:s,name:i,reader:n,writer:o}=r;return{[i]:{get(){var e=this.data.get(s);return null!==e?n(e):r.defaultValue},set(e){void 0===e?this.data.delete(s):this.data.set(s,o(e))}},["has"+l(i)]:{get(){return this.data.has(s)||r.hasCustomDefaultValue}}}}(t)),{valueDescriptorMap:{get(){return t.reduce((e,t)=>{var t=T(t,this.identifier),r=this.data.getAttributeNameForKey(t.key);return Object.assign(e,{[r]:t})},{})}}})},function(e){return E(e,"outlets").reduce((e,t)=>{return Object.assign(e,{[(e=s(r=t))+"Outlet"]:{get(){var e=this.outlets.find(r),t=this.outlets.getSelectorForOutletName(r);if(e){e=C(this,e,r);if(e)return e;throw new Error(`The provided outlet element is missing an outlet controller "${r}" instance for host controller "${this.identifier}"`)}throw new Error(`Missing outlet element "${r}" for host controller "${this.identifier}". Stimulus couldn't find a matching outlet element using selector "${t}".`)}},[e+"Outlets"]:{get(){var e=this.outlets.findAll(r);return 0{var t=C(this,e,r);if(t)return t;console.warn(`The provided outlet element is missing an outlet controller "${r}" instance for host controller "${this.identifier}"`,e)}).filter(e=>e):[]}},[e+"OutletElement"]:{get(){var e=this.outlets.find(r),t=this.outlets.getSelectorForOutletName(r);if(e)return e;throw new Error(`Missing outlet element "${r}" for host controller "${this.identifier}". Stimulus couldn't find a matching outlet element using selector "${t}".`)}},[e+"OutletElements"]:{get(){return this.outlets.findAll(r)}},[`has${l(e)}Outlet`]:{get(){return this.outlets.has(r)}}});var r},{})}],V.targets=[],V.outlets=[],V.values={},e.Application=oe,e.AttributeObserver=m,e.Context=M,e.Controller=V,e.ElementObserver=d,e.IndexedMultimap=z,e.Multimap=v,e.SelectorObserver=b,e.StringMapObserver=y,e.TokenListObserver=O,e.ValueListObserver=A,e.add=r,e.defaultSchema=N,e.del=g,e.fetch=p,e.prune=f,Object.defineProperty(e,"__esModule",{value:!0})});
diff --git a/tests/fuzz/20_L1_Open_Requirements_Tool_202511/assets/table_vew.css b/tests/fuzz/20_L1_Open_Requirements_Tool_202511/assets/table_vew.css
new file mode 100644
index 0000000..263332e
--- /dev/null
+++ b/tests/fuzz/20_L1_Open_Requirements_Tool_202511/assets/table_vew.css
@@ -0,0 +1,79 @@
+/* ultimate table view */
+
+.content-view-table {
+ border-collapse: collapse;
+ width: 100%;
+ background-color: var(--color-bg-contrast);
+}
+
+/* .content-view-table td,
+.content-view-table th, */
+.content-view-th,
+.content-view-td {
+ padding: .5rem 1rem;
+ border: 1px solid #666;
+ vertical-align: top;
+}
+
+.content-view-th {
+ text-align: left;
+ text-transform: uppercase;
+ background-color: var(--color-border);
+ font-size: .85em;
+ font-weight: bold;
+}
+
+.content-view-td-type,
+.content-view-td-meta {
+ background-color: var(--color-bg-main);
+ font-size: .85em;
+}
+
+.content-view-td-type {
+ background-color: var(--color-bg-main);
+ text-align: left;
+ font-weight: normal;
+ text-transform: uppercase;
+}
+
+.content-view-table div.document {
+ /* TODO */
+ display: block;
+ max-width: 900px;
+}
+
+.content-view-table p:first-child {
+ margin-top: 0;
+}
+
+.content-view-table p:last-child {
+ margin-bottom: 0;
+}
+
+.content-view-td:empty {
+ width: 1%;
+}
+
+.content-view-td-content:not(:empty) {
+ min-width: 333px;
+ width: 30%;
+}
+
+.content-view-td-title:not(:empty) {
+ font-weight: bold;
+ min-width: 264px;
+}
+
+.content-view-td-related:not(:empty) {
+ min-width: 264px;
+}
+
+.content-view-td-related,
+.content-view-td-related > ul.requirement__link {
+ font-size: .85rem;
+ margin-top: 0;
+}
+
+.content-view-td-related > ul.requirement__link:last-child {
+ margin-bottom: 0;
+}
diff --git a/tests/fuzz/20_L1_Open_Requirements_Tool_202511/assets/toc_highlighting.js b/tests/fuzz/20_L1_Open_Requirements_Tool_202511/assets/toc_highlighting.js
new file mode 100644
index 0000000..fb96016
--- /dev/null
+++ b/tests/fuzz/20_L1_Open_Requirements_Tool_202511/assets/toc_highlighting.js
@@ -0,0 +1,291 @@
+const TOC_HIGHLIGHT_DEBUG = false;
+
+const TOC_FRAME_SELECTOR = 'turbo-frame#frame-toc'; // updating
+const TOC_LIST_SELECTOR = 'ul#toc';
+const TOC_ELEMENT_SELECTOR = 'a';
+const CONTENT_FRAME_SELECTOR = 'turbo-frame#frame_document_content'; // replacing => parentNode is needed
+const CONTENT_ELEMENT_SELECTOR = 'sdoc-anchor';
+
+let tocHighlightingState = {
+ data: {},
+ links: null,
+ anchors: null,
+ contentFrameTop: undefined,
+ closerForFolder: {},
+ folderSet: new Set(),
+};
+
+function resetState() {
+ tocHighlightingState.data = {};
+ tocHighlightingState.links = null;
+ tocHighlightingState.anchors = null;
+ tocHighlightingState.closerForFolder = {};
+ tocHighlightingState.folderSet = new Set();
+}
+
+window.addEventListener("hashchange", handleHashChange);
+window.addEventListener("load",function(){
+
+ // * Frames are stable and we define them once.
+ const tocFrame = document.querySelector(TOC_FRAME_SELECTOR);
+ const tocList = tocFrame ? tocFrame.querySelector(TOC_LIST_SELECTOR) : null;
+ const contentFrame = document.querySelector(CONTENT_FRAME_SELECTOR)?.parentNode;
+
+ if(!tocFrame || !tocList || !contentFrame) { return }
+
+ // ! depends on TOC markup
+ tocHighlightingState.contentFrameTop = contentFrame.offsetParent
+ ? contentFrame.offsetTop
+ : contentFrame.parentNode.offsetTop;
+
+ const anchorObserver = new IntersectionObserver(
+ handleIntersect,
+ {
+ root: null,
+ rootMargin: "0px",
+ });
+
+ // * Then we will refresh when the TOC tree is updated&
+ // * The content in the tocFrame frame will mutate:
+ const mutatingFrame = tocFrame;
+ new MutationObserver(function (mutationsList, observer) {
+ // * Use requestAnimationFrame to put highlightTOC
+ // * at the end of the event queue and to ensure
+ // * the code runs after all DOM changes have been applied.
+ requestAnimationFrame(() => {
+ highlightTOC(tocFrame, contentFrame, anchorObserver);
+ })
+ }).observe(
+ mutatingFrame,
+ {
+ // * We're looking at an updatable frame (mutates its contents,
+ // * and we don't care what mutations were made inside):
+ childList: true,
+ // attributes: true,
+ // characterData: true,
+ // subtree: true
+ }
+ );
+
+ // * Call for the first time only if the TOC actually contains items.
+ if (tocList && tocList.querySelector(TOC_ELEMENT_SELECTOR)) {
+ highlightTOC(tocFrame, contentFrame, anchorObserver);
+ }
+
+},false);
+
+function highlightTOC(tocFrame, contentFrame, anchorObserver) {
+
+ resetState();
+ processLinkList(tocFrame);
+ processAnchorList(contentFrame, anchorObserver);
+ handleHashChange();
+
+ TOC_HIGHLIGHT_DEBUG && console.log(tocHighlightingState);
+}
+
+function handleHashChange() {
+ const hash = window.location.hash;
+ const match = hash.match(/#(.*)/);
+ const fragment = match ? match[1] : null;
+
+ // Guard: no links collected yet (e.g., empty TOC or init race)
+ if (!tocHighlightingState.links || typeof tocHighlightingState.links.forEach !== 'function') {
+ return;
+ }
+
+ tocHighlightingState.links.forEach(link => {
+ targetItem(link, false)
+ });
+ // * When updating the hash
+ // * and there's a fragment,
+ fragment
+ // * and the corresponding link-anchor pair is registered,
+ && tocHighlightingState.data[fragment]
+ // * highlight the corresponding link.
+ && targetItem(tocHighlightingState.data[fragment].link)
+}
+
+function processLinkList(tocFrame) {
+ // * Collects all links in the TOC
+ tocHighlightingState.links = tocFrame.querySelectorAll(TOC_ELEMENT_SELECTOR);
+ if (!tocHighlightingState.links || tocHighlightingState.links.length === 0) {
+ return;
+ }
+ tocHighlightingState.links.length
+ && tocHighlightingState.links.forEach(link => {
+ const id = link.getAttribute('anchor');
+ tocHighlightingState.data[id] = {
+ 'link': link,
+ ...tocHighlightingState.data[id]
+ }
+
+ // ! depends on TOC markup
+ // is link in collapsible node and precedes the UL
+ // ! expected UL or null
+ const ul = link.nextSibling;
+
+ if (ul && ul.nodeName === 'UL') {
+ // register folder
+ tocHighlightingState.folderSet.add(id);
+
+ // register closer
+ const lastLink = findDeepestLastChild(ul);
+ const lastAnchor = lastLink.getAttribute('anchor');
+
+
+ if (!tocHighlightingState.closerForFolder[lastAnchor]) {
+ tocHighlightingState.closerForFolder[lastAnchor] = [];
+ }
+ tocHighlightingState.closerForFolder[lastAnchor].push(id);
+ }
+ });
+}
+
+function processAnchorList(contentFrame, anchorObserver) {
+ anchorObserver.disconnect(); // FIXME don`t work: have to hack at #rootBounds_null
+
+ // * Collects all anchors in the document
+ tocHighlightingState.anchors = null;
+ tocHighlightingState.anchors = contentFrame.querySelectorAll(CONTENT_ELEMENT_SELECTOR);
+ tocHighlightingState.anchors.length
+ && tocHighlightingState.anchors.forEach(anchor => {
+ const id = anchor.id;
+ tocHighlightingState.data[id] = {
+ 'anchor': anchor,
+ ...tocHighlightingState.data[id]
+ };
+ // * Adds an observer for the position of the anchor
+ anchorObserver.observe(anchor);
+ });
+}
+
+function handleIntersect(entries, observer) {
+
+ entries.forEach((entry) => {
+
+ // #rootBounds_null
+ // rootBounds: null
+ // after frame reload and before init
+ if(!entry.rootBounds) {
+ return
+ }
+
+ const anchor = entry.target.id;
+ // * For anchors that go into the viewport,
+ // * finds the corresponding links
+ const link = tocHighlightingState.data[anchor].link;
+
+ // * if there is no menu item for the section in the TOC
+ if(!link) {
+ return
+ }
+
+ if (entry.isIntersecting) { //! entry.intersectionRatio > 0 -- it happens to be equal to zero at the intersection!
+
+ TOC_HIGHLIGHT_DEBUG && console.group('🔶', entry.isIntersecting, entry.intersectionRatio, anchor, entry.intersectionRect.height);
+ // * and highlights them in the TOC,
+ fireItem(link)
+
+ // * semi-highlights folder in the TOC,
+ if (tocHighlightingState.folderSet.has(anchor)) {
+ TOC_HIGHLIGHT_DEBUG && console.log('🔴', anchor, '(visible folder)', );
+ fireFolder(link)
+ }
+
+ // * semi-highlights closer`s parent folder in the TOC,
+ if (tocHighlightingState.closerForFolder[anchor]) {
+ tocHighlightingState.closerForFolder[anchor].forEach(id => {
+ TOC_HIGHLIGHT_DEBUG && console.log(`🔴`, id, `(from ${anchor})`);
+ fireFolder(tocHighlightingState.data[id].link)
+ })
+ }
+ TOC_HIGHLIGHT_DEBUG && console.groupEnd();
+
+ } else {
+
+ TOC_HIGHLIGHT_DEBUG && console.group('🔹', entry.isIntersecting, entry.intersectionRatio, anchor);
+ // * or cancels highlighting for the rest of the links.
+ fireItem(link, false);
+
+ if(
+ // * If the node goes down ⬇️ off the screen
+ entry.boundingClientRect.bottom >= entry.rootBounds.bottom
+ // * and it's a folder
+ && tocHighlightingState.folderSet.has(anchor)
+ ) {
+ // ** remove highlights from folder in the TOC
+ TOC_HIGHLIGHT_DEBUG && console.log(`⚫ ⬇️`, anchor);
+ fireFolder(link, false)
+ }
+
+ if(
+ // * If the node goes up ⬆️ off the screen
+ entry.boundingClientRect.y < tocHighlightingState.contentFrameTop
+ // * and this is the last child of the section
+ && tocHighlightingState.closerForFolder[anchor]
+ ) {
+ // * When the LAST CHILD of the section disappears
+ // * over the upper boundary ( < tocHighlightingState.contentFrameTop),
+ // * strictly speaking, this occurs when the lower bound disappears:
+ // * entry.boundingClientRect.bottom.
+ // * But we will use the upper bound, entry.boundingClientRect.y
+ // * which will be less than or equal to the lower bound.
+
+ // ** remove highlights from closer`s parent folder in the TOC
+ tocHighlightingState.closerForFolder[anchor].forEach(id => {
+ TOC_HIGHLIGHT_DEBUG && console.log(`⚫ ⬆️`, id,);
+ fireFolder(tocHighlightingState.data[id].link, false)
+ });
+ }
+
+ TOC_HIGHLIGHT_DEBUG && console.groupEnd();
+ }
+ });
+
+}
+
+function findDeepestLastChild(element) {
+ // ! depends on TOC markup
+ // ul > li > div + a + ul > ...
+ // ul > li > a
+ // > li > a <---------------***
+ if (element.nodeName === 'A') {
+ return element;
+ }
+ const children = element.children;
+ if (children && children.length > 0) {
+ return findDeepestLastChild([...children].at(-1))
+ } else {
+ return element;
+ }
+}
+
+function targetItem(element, on = true) {
+ if (!element) { return } // Guard against race conditions:
+ // hashchange or intersection events may fire
+ // before the TOC is fully built, resulting in undefined link elements.
+ if(on) {
+ element.setAttribute('targeted', '');
+ } else {
+ element.removeAttribute('targeted');
+ }
+}
+
+function fireItem(element, on = true) {
+ if (!element) { return } // Guard against race conditions
+ if(on) {
+ element.setAttribute('intersected', '');
+ } else {
+ element.removeAttribute('intersected');
+ }
+}
+
+function fireFolder(element, on = true) {
+ if (!element) { return } // Guard against race conditions
+ if(on) {
+ element.setAttribute('parented', '');
+ } else {
+ element.removeAttribute('parented');
+ }
+}
diff --git a/tests/fuzz/20_L1_Open_Requirements_Tool_202511/assets/traceability_matrix_screen.css b/tests/fuzz/20_L1_Open_Requirements_Tool_202511/assets/traceability_matrix_screen.css
new file mode 100644
index 0000000..6c9c279
--- /dev/null
+++ b/tests/fuzz/20_L1_Open_Requirements_Tool_202511/assets/traceability_matrix_screen.css
@@ -0,0 +1,148 @@
+.traceability_matrix {
+ --traceability_matrix-thead-height: calc(4 * var(--base-rhythm));
+
+
+ display: table;
+ border-collapse: collapse;
+}
+
+.traceability_matrix__anchor {
+ /* for Fixed Headers + Section Anchors */
+ scroll-snap-margin-top: var(--base-gap);
+ scroll-margin-top: var(--base-gap);
+}
+
+.traceability_matrix .traceability_matrix__thead {
+ position: sticky;
+ top: calc(-1 * var(--traceability_matrix-thead-height));
+ z-index: 2;
+ background-color: var(--color-bg-main);
+}
+
+.traceability_matrix .traceability_matrix__thead::before {
+ content: '';
+ position: absolute;
+ top: calc(-1 * var(--base-gap));
+ left: calc(-1 * var(--base-gap));
+ right: calc(-1 * var(--base-gap));
+ bottom: 0;
+ z-index: 0;
+ background-color: var(--color-bg-main);
+}
+
+.traceability_matrix__thead th {
+ height: var(--traceability_matrix-thead-height);
+ text-align: left;
+ vertical-align: middle;
+ line-height: 1;
+ position: relative;
+ background-color: var(--color-bg-secondary-invert);
+ padding-left: var(--base-rhythm);
+ border: 1px solid var(--color-border);
+}
+
+.traceability_matrix td {
+ border: 1px solid var(--color-border);
+ background-color: var(--color-bg-contrast);
+ vertical-align: top;
+}
+
+td.traceability_matrix__document {
+ position: sticky;
+ padding: 0;
+ top: 0;
+ z-index: 1;
+}
+
+.traceability_matrix__placeholder {
+ padding: var(--base-rhythm);
+ text-align: center;
+ font-size: var(--font-size-sm);
+}
+
+td.traceability_matrix__null {
+ height: calc(4 * var(--base-rhythm));
+ background-color: var(--color-bg-main);
+ border: none;
+}
+
+.traceability_matrix__document_line {
+ display: flex;
+ align-items: center;
+ justify-content: flex-start;
+ column-gap: calc(2 * var(--base-rhythm));
+ font-size: var(--font-size-l);
+ font-weight: 600;
+ line-height: 1.2;
+ width: 100%;
+
+ padding: var(--base-rhythm);
+ padding-top: calc(1.5 * var(--base-rhythm));
+
+ border-bottom: 1px solid var(--color-border);
+}
+
+.traceability_matrix__document_stat {
+ margin-left: auto;
+}
+
+.traceability_matrix__requirement {
+ display: block;
+ position: relative;
+ font-size: var(--font-size-sm);
+ line-height: 1.2;
+ padding: var(--base-rhythm);
+}
+
+.traceability_matrix__file {
+ position: relative;
+ font-size: var(--font-size-sm);
+ line-height: 1.2;
+ margin-top: var(--base-rhythm);
+ margin-bottom: var(--base-rhythm);
+ padding-right: var(--base-rhythm);
+}
+
+.traceability_matrix__file a {
+ /* overflow-wrap: break-word; */
+ overflow-wrap: anywhere;
+ color: var(--color-link);
+ text-decoration: none;
+}
+
+.traceability_matrix__file a:hover {
+ color: var(--color-hover);
+}
+
+[with_relation] {
+ padding-left: calc(4 * var(--base-rhythm));
+}
+
+[with_relation]::before {
+ content: '';
+ font-size: var(--font-size);
+ line-height: 1;
+ position: absolute;
+ left: var(--base-rhythm);
+}
+
+.traceability_matrix__requirement[with_relation]::before {
+ top: var(--base-rhythm);
+}
+
+.traceability_matrix__file[with_relation]::before {
+ top: 0
+}
+
+/* ← → */
+[with_relation="parent"]::before {
+ content: '→';
+}
+
+[with_relation="child"]::before {
+ content: '←';
+}
+
+[with_relation="file"]::before {
+ content: '→';
+}
diff --git a/tests/fuzz/20_L1_Open_Requirements_Tool_202511/assets/traceability_matrix_screen.js b/tests/fuzz/20_L1_Open_Requirements_Tool_202511/assets/traceability_matrix_screen.js
new file mode 100644
index 0000000..9be993e
--- /dev/null
+++ b/tests/fuzz/20_L1_Open_Requirements_Tool_202511/assets/traceability_matrix_screen.js
@@ -0,0 +1,48 @@
+// @relation(SDOC-SRS-112, scope=file)
+
+const SELECTOR = '[js-requirements-coverage]';
+
+const __log = (topic, ...payload) => {
+ console.log(`%c ${topic} `, 'background:yellow;color:black',
+ ...payload
+ );
+}
+
+function markSame(newUid, state, arr) {
+ // __log('state', state.currentUid);
+ state.currentUid && arr[state.currentUid].forEach(element => element.classList.remove('highlighted'));
+ state.currentUid = newUid;
+ arr[newUid].forEach(element => element.classList.add('highlighted'));
+
+}
+
+window.addEventListener("load", function () {
+ // __log(
+ // 'requirements-coverage',
+ // 'test'
+ // )
+
+ const state = {
+ currentUid: null
+ }
+
+ // https://stackoverflow.com/questions/32249997/how-to-check-if-data-attribute-exist-with-plain-javascript/32250073
+ const reqs = [...document.querySelectorAll(SELECTOR)]
+ .reduce((acc, req) => {
+ if (req.hasAttribute('data-uid')) {
+ req.addEventListener('click', () => markSame(uid, state, reqs));
+ const uid = req.dataset.uid;
+ acc[uid] = acc[uid] ? [...acc[uid], req] : [req];
+ } else {
+ req.classList.add('nouid')
+ acc.nouid.push(req);
+ }
+ return acc
+ }, { nouid: [] });
+
+ // __log(
+ // '--',
+ // reqs
+ // )
+
+});
diff --git a/tests/fuzz/20_L1_Open_Requirements_Tool_202511/assets/tree(not_in_use).css b/tests/fuzz/20_L1_Open_Requirements_Tool_202511/assets/tree(not_in_use).css
new file mode 100644
index 0000000..acd2a13
--- /dev/null
+++ b/tests/fuzz/20_L1_Open_Requirements_Tool_202511/assets/tree(not_in_use).css
@@ -0,0 +1,146 @@
+.std-tree {
+ --tree-font-size: 16px;
+ --tree-line-height: calc(var(--tree-font-size)*1.25);
+ --tree-level-padding: calc(var(--tree-font-size)*1.5);
+ --tree-cell-padding: calc(var(--tree-font-size)*0.5);
+
+ --tree-level-line-width: 1px;
+
+ --tree-color-line: #808080;
+ --tree-color-fg: var(--color-fg-main, #444444);
+ --tree-color-bg: var(--color-bg-main, #F2F5F9);
+ --tree-color-row-hover-bg: var(--color-bg-contrast, #FFFFFF);
+ --tree-btn-bg-color: var(--color-bg-contrast, #FFFFFF);
+
+ --tree-half-sell-height: calc( var(--tree-line-height)/2 + var(--tree-cell-padding) );
+
+ --tree-ico-size: var(--tree-font-size, 1rem);
+
+ --tree-max-width: 800px;
+}
+
+
+/* tree */
+.std-tree {
+ font-size: var(--tree-font-size, 1rem);
+ line-height: var(--tree-line-height, 1.25);
+ color: var(--tree-color-fg, #444444);
+
+ position: relative;
+ width: -moz-fit-content;
+ width: fit-content;
+ /* margin: 0 auto; */
+}
+
+.std-tree ul {
+ list-style: none;
+ width: 100%;
+ padding: 0;
+ margin: 0;
+}
+
+.std-tree li {
+ position: relative;
+ padding-left: var(--tree-level-padding);
+}
+
+.std-tree ul ul > li::before {
+ content: '';
+ position: absolute;
+ left: calc(var(--tree-ico-size)*0.5 - var(--tree-level-padding));
+ top: calc(var(--tree-ico-size)*(-0.5));
+ height: 100%;
+ border-left: 1px solid var(--tree-color-line);
+}
+
+.std-tree ul > li:last-child::before {
+ height: calc(var(--tree-ico-size) + var(--tree-cell-padding));
+}
+
+.std-tree_ico {
+ display: inline-flex;
+ align-items: center;
+
+ position: absolute;
+ left: 0;
+ top: calc(var(--tree-cell-padding));
+}
+
+ ul ul .std-tree_ico::before {
+ content: '';
+ position: absolute;
+ left: calc(var(--tree-ico-size)*0.5 - var(--tree-level-padding));
+ right: 100%;
+ border-bottom: 1px solid var(--tree-color-line);
+ }
+
+ .std-tree_ico svg {
+ display: inline-block;
+ width: var(--tree-ico-size);
+ height: var(--tree-ico-size);
+
+ fill: var(--tree-color-line);
+ }
+
+ .std-tree_row {
+ padding-top: var(--tree-cell-padding);
+ padding-bottom: var(--tree-cell-padding);
+ padding-left: var(--tree-cell-padding);
+
+ display: flex;
+ justify-content: space-between;
+ }
+
+ .std-tree_folder {
+ font-weight: bold;
+ display: flex;
+ }
+
+ .std-tree_file {
+ order: 1;
+ flex-grow: 1;
+ }
+
+ .std-tree_file__title {
+ font-size: 1.25em;
+ color: #000;
+ transition: color .2s ease;
+ }
+
+ .std-tree_file-link:hover .std-tree_file__title {
+ color: var(--color-fg-accent);
+ }
+
+ .std-tree_file__name {
+ font-size: 0.85rem;
+ line-height: 1.2;
+ color: var(--color-fg-secondary);
+ margin-top: 0.25rem;
+ }
+
+ .std-tree_desc {
+ position: relative;
+ top: -2px;
+ color: #000;
+ }
+
+ .std-tree_name {
+ font-size: 0.85rem;
+ line-height: 1.2;
+ color: #666;
+ }
+
+ .std-tree_aside {
+ width: -moz-fit-content;
+ width: fit-content;
+ padding-left: 20px;
+ display: flex;
+ justify-content: space-between;
+ align-items: flex-start;
+ order: 3;
+ }
+
+ .std-tree_file-link {
+ position: relative;
+ top: -2px;
+ }
diff --git a/tests/fuzz/20_L1_Open_Requirements_Tool_202511/assets/turbo.min.js b/tests/fuzz/20_L1_Open_Requirements_Tool_202511/assets/turbo.min.js
new file mode 100644
index 0000000..ee8fdf3
--- /dev/null
+++ b/tests/fuzz/20_L1_Open_Requirements_Tool_202511/assets/turbo.min.js
@@ -0,0 +1,24 @@
+!function(){if(void 0!==window.Reflect&&void 0!==window.customElements&&!window.customElements.polyfillWrapFlushCallback){const e=HTMLElement,t=function(){return Reflect.construct(e,[],this.constructor)};window.HTMLElement=t,HTMLElement.prototype=e.prototype,HTMLElement.prototype.constructor=HTMLElement,Object.setPrototypeOf(HTMLElement,e)}}(),function(e){function r(e,t,s){throw new e("Failed to execute 'requestSubmit' on 'HTMLFormElement': "+t+".",s)}"function"!=typeof e.requestSubmit&&(e.requestSubmit=function(e){var t,s;e?(s=this,(t=e)instanceof HTMLElement||r(TypeError,"parameter 1 is not of type 'HTMLElement'"),"submit"!=t.type&&r(TypeError,"The specified element is not a submit button"),t.form!=s&&r(DOMException,"The specified element is not owned by this form element","NotFoundError"),e.click()):((e=document.createElement("input")).type="submit",e.hidden=!0,this.appendChild(e),e.click(),this.removeChild(e))})}(HTMLFormElement.prototype);const submittersByForm=new WeakMap;function findSubmitterFromClickTarget(e){e=e instanceof Element?e:e instanceof Node?e.parentElement:null,e=e?e.closest("input, button"):null;return"submit"==(null==e?void 0:e.type)?e:null}function clickCaptured(e){e=findSubmitterFromClickTarget(e.target);e&&e.form&&submittersByForm.set(e.form,e)}var FrameLoadingStyle,FetchMethod,FormSubmissionState,FormEnctype,TimingMetric,VisitState,SystemStatusCode,PageStage;!function(){if(!("submitter"in Event.prototype)){let e;if("SubmitEvent"in window&&/Apple Computer/.test(navigator.vendor))e=window.SubmitEvent.prototype;else{if("SubmitEvent"in window)return;e=window.Event.prototype}addEventListener("click",clickCaptured,!0),Object.defineProperty(e,"submitter",{get(){if("submit"==this.type&&this.target instanceof HTMLFormElement)return submittersByForm.get(this.target)}})}}(),function(e){e.eager="eager",e.lazy="lazy"}(FrameLoadingStyle=FrameLoadingStyle||{});class FrameElement extends HTMLElement{constructor(){super(),this.loaded=Promise.resolve(),this.delegate=new FrameElement.delegateConstructor(this)}static get observedAttributes(){return["disabled","loading","src"]}connectedCallback(){this.delegate.connect()}disconnectedCallback(){this.delegate.disconnect()}reload(){var e=this["src"];this.src=null,this.src=e}attributeChangedCallback(e){"loading"==e?this.delegate.loadingStyleChanged():"src"==e?this.delegate.sourceURLChanged():this.delegate.disabledChanged()}get src(){return this.getAttribute("src")}set src(e){e?this.setAttribute("src",e):this.removeAttribute("src")}get loading(){return frameLoadingStyleFromString(this.getAttribute("loading")||"")}set loading(e){e?this.setAttribute("loading",e):this.removeAttribute("loading")}get disabled(){return this.hasAttribute("disabled")}set disabled(e){e?this.setAttribute("disabled",""):this.removeAttribute("disabled")}get autoscroll(){return this.hasAttribute("autoscroll")}set autoscroll(e){e?this.setAttribute("autoscroll",""):this.removeAttribute("autoscroll")}get complete(){return!this.delegate.isLoading}get isActive(){return this.ownerDocument===document&&!this.isPreview}get isPreview(){var e;return null==(e=null==(e=this.ownerDocument)?void 0:e.documentElement)?void 0:e.hasAttribute("data-turbo-preview")}}function frameLoadingStyleFromString(e){return"lazy"!==e.toLowerCase()?FrameLoadingStyle.eager:FrameLoadingStyle.lazy}function expandURL(e){return new URL(e.toString(),document.baseURI)}function getAnchor(e){return e.hash?e.hash.slice(1):(e=e.href.match(/#(.*)$/))?e[1]:void 0}function getAction(e,t){return expandURL((null==t?void 0:t.getAttribute("formaction"))||e.getAttribute("action")||e.action)}function getExtension(e){return(getLastPathComponent(e).match(/\.[^.]*$/)||[])[0]||""}function isHTML(e){return!!getExtension(e).match(/^(?:|\.(?:htm|html|xhtml))$/)}function isPrefixedBy(e,t){t=getPrefix(t);return e.href===expandURL(t).href||e.href.startsWith(t)}function locationIsVisitable(e,t){return isPrefixedBy(e,t)&&isHTML(e)}function getRequestURL(e){var t=getAnchor(e);return null!=t?e.href.slice(0,-(t.length+1)):e.href}function toCacheKey(e){return getRequestURL(e)}function urlsAreEqual(e,t){return expandURL(e).href==expandURL(t).href}function getPathComponents(e){return e.pathname.split("/").slice(1)}function getLastPathComponent(e){return getPathComponents(e).slice(-1)[0]}function getPrefix(e){return addTrailingSlash(e.origin+e.pathname)}function addTrailingSlash(e){return e.endsWith("/")?e:e+"/"}class FetchResponse{constructor(e){this.response=e}get succeeded(){return this.response.ok}get failed(){return!this.succeeded}get clientError(){return 400<=this.statusCode&&this.statusCode<=499}get serverError(){return 500<=this.statusCode&&this.statusCode<=599}get redirected(){return this.response.redirected}get location(){return expandURL(this.response.url)}get isHTML(){return this.contentType&&this.contentType.match(/^(?:text\/([^\s;,]+\b)?html|application\/xhtml\+xml)\b/)}get statusCode(){return this.response.status}get contentType(){return this.header("Content-Type")}get responseText(){return this.response.clone().text()}get responseHTML(){return this.isHTML?this.response.clone().text():Promise.resolve(void 0)}header(e){return this.response.headers.get(e)}}function dispatch(e,{target:t,cancelable:s,detail:r}={}){e=new CustomEvent(e,{cancelable:s,bubbles:!0,detail:r});return(t&&t.isConnected?t:document.documentElement).dispatchEvent(e),e}function nextAnimationFrame(){return new Promise(e=>requestAnimationFrame(()=>e()))}function nextEventLoopTick(){return new Promise(e=>setTimeout(()=>e(),0))}function nextMicrotask(){return Promise.resolve()}function parseHTMLDocument(e=""){return(new DOMParser).parseFromString(e,"text/html")}function unindent(e,...t){e=interpolate(e,t).replace(/^\n/,"").split("\n"),t=e[0].match(/^\s+/);const s=t?t[0].length:0;return e.map(e=>e.slice(s)).join("\n")}function interpolate(e,r){return e.reduce((e,t,s)=>{return e+t+(null==r[s]?"":r[s])},"")}function uuid(){return Array.apply(null,{length:36}).map((e,t)=>8==t||13==t||18==t||23==t?"-":14==t?"4":(19==t?Math.floor(4*Math.random())+8:Math.floor(15*Math.random())).toString(16)).join("")}function getAttribute(t,...e){for(const s of e.map(e=>null==e?void 0:e.getAttribute(t)))if("string"==typeof s)return s;return null}function markAsBusy(...e){for(const t of e)"turbo-frame"==t.localName&&t.setAttribute("busy",""),t.setAttribute("aria-busy","true")}function clearBusyState(...e){for(const t of e)"turbo-frame"==t.localName&&t.removeAttribute("busy"),t.removeAttribute("aria-busy")}function fetchMethodFromString(e){switch(e.toLowerCase()){case"get":return FetchMethod.get;case"post":return FetchMethod.post;case"put":return FetchMethod.put;case"patch":return FetchMethod.patch;case"delete":return FetchMethod.delete}}!function(e){e[e.get=0]="get",e[e.post=1]="post",e[e.put=2]="put",e[e.patch=3]="patch",e[e.delete=4]="delete"}(FetchMethod=FetchMethod||{});class FetchRequest{constructor(e,t,s,r=new URLSearchParams,i=null){this.abortController=new AbortController,this.resolveRequestPromise=e=>{},this.delegate=e,this.method=t,this.headers=this.defaultHeaders,this.body=r,this.url=s,this.target=i}get location(){return this.url}get params(){return this.url.searchParams}get entries(){return this.body?Array.from(this.body.entries()):[]}cancel(){this.abortController.abort()}async perform(){var e,t,s=this["fetchOptions"];null!=(t=(e=this.delegate).prepareHeadersForRequest)&&t.call(e,this.headers,this),await this.allowRequestToBeIntercepted(s);try{this.delegate.requestStarted(this);var r=await fetch(this.url.href,s);return await this.receive(r)}catch(e){if("AbortError"!==e.name)throw this.delegate.requestErrored(this,e),e}finally{this.delegate.requestFinished(this)}}async receive(e){e=new FetchResponse(e);return dispatch("turbo:before-fetch-response",{cancelable:!0,detail:{fetchResponse:e},target:this.target}).defaultPrevented?this.delegate.requestPreventedHandlingResponse(this,e):e.succeeded?this.delegate.requestSucceededWithResponse(this,e):this.delegate.requestFailedWithResponse(this,e),e}get fetchOptions(){var e;return{method:FetchMethod[this.method].toUpperCase(),credentials:"same-origin",headers:this.headers,redirect:"follow",body:this.isIdempotent?null:this.body,signal:this.abortSignal,referrer:null==(e=this.delegate.referrer)?void 0:e.href}}get defaultHeaders(){return{Accept:"text/html, application/xhtml+xml"}}get isIdempotent(){return this.method==FetchMethod.get}get abortSignal(){return this.abortController.signal}async allowRequestToBeIntercepted(e){var t=new Promise(e=>this.resolveRequestPromise=e);dispatch("turbo:before-fetch-request",{cancelable:!0,detail:{fetchOptions:e,url:this.url,resume:this.resolveRequestPromise},target:this.target}).defaultPrevented&&await t}}class AppearanceObserver{constructor(e,t){this.started=!1,this.intersect=e=>{e=e.slice(-1)[0];null!=e&&e.isIntersecting&&this.delegate.elementAppearedInViewport(this.element)},this.delegate=e,this.element=t,this.intersectionObserver=new IntersectionObserver(this.intersect)}start(){this.started||(this.started=!0,this.intersectionObserver.observe(this.element))}stop(){this.started&&(this.started=!1,this.intersectionObserver.unobserve(this.element))}}class StreamMessage{constructor(e){this.templateElement=document.createElement("template"),this.templateElement.innerHTML=e}static wrap(e){return"string"==typeof e?new this(e):e}get fragment(){var e=document.createDocumentFragment();for(const t of this.foreignElements)e.appendChild(document.importNode(t,!0));return e}get foreignElements(){return this.templateChildren.reduce((e,t)=>"turbo-stream"==t.tagName.toLowerCase()?[...e,t]:e,[])}get templateChildren(){return Array.from(this.templateElement.content.children)}}function formEnctypeFromString(e){switch(e.toLowerCase()){case FormEnctype.multipart:return FormEnctype.multipart;case FormEnctype.plain:return FormEnctype.plain;default:return FormEnctype.urlEncoded}}StreamMessage.contentType="text/vnd.turbo-stream.html",function(e){e[e.initialized=0]="initialized",e[e.requesting=1]="requesting",e[e.waiting=2]="waiting",e[e.receiving=3]="receiving",e[e.stopping=4]="stopping",e[e.stopped=5]="stopped"}(FormSubmissionState=FormSubmissionState||{}),function(e){e.urlEncoded="application/x-www-form-urlencoded",e.multipart="multipart/form-data",e.plain="text/plain"}(FormEnctype=FormEnctype||{});class FormSubmission{constructor(e,t,s,r=!1){this.state=FormSubmissionState.initialized,this.delegate=e,this.formElement=t,this.submitter=s,this.formData=buildFormData(t,s),this.location=expandURL(this.action),this.method==FetchMethod.get&&mergeFormDataEntries(this.location,[...this.body.entries()]),this.fetchRequest=new FetchRequest(this,this.method,this.location,this.body,this.formElement),this.mustRedirect=r}static confirmMethod(e,t){return confirm(e)}get method(){var e;return fetchMethodFromString(((null==(e=this.submitter)?void 0:e.getAttribute("formmethod"))||this.formElement.getAttribute("method")||"").toLowerCase())||FetchMethod.get}get action(){var e,t="string"==typeof this.formElement.action?this.formElement.action:null;return(null==(e=this.submitter)?void 0:e.getAttribute("formaction"))||this.formElement.getAttribute("action")||t||""}get body(){return this.enctype==FormEnctype.urlEncoded||this.method==FetchMethod.get?new URLSearchParams(this.stringFormData):this.formData}get enctype(){var e;return formEnctypeFromString((null==(e=this.submitter)?void 0:e.getAttribute("formenctype"))||this.formElement.enctype)}get isIdempotent(){return this.fetchRequest.isIdempotent}get stringFormData(){return[...this.formData].reduce((e,[t,s])=>e.concat("string"==typeof s?[[t,s]]:[]),[])}get confirmationMessage(){return this.formElement.getAttribute("data-turbo-confirm")}get needsConfirmation(){return null!==this.confirmationMessage}async start(){var{initialized:e,requesting:t}=FormSubmissionState;if(this.needsConfirmation&&!FormSubmission.confirmMethod(this.confirmationMessage,this.formElement))return;if(this.state==e)return this.state=t,this.fetchRequest.perform()}stop(){var{stopping:e,stopped:t}=FormSubmissionState;if(this.state!=e&&this.state!=t)return this.state=e,this.fetchRequest.cancel(),!0}prepareHeadersForRequest(e,t){t.isIdempotent||((t=getCookieValue(getMetaContent("csrf-param"))||getMetaContent("csrf-token"))&&(e["X-CSRF-Token"]=t),e.Accept=[StreamMessage.contentType,e.Accept].join(", "))}requestStarted(e){var t;this.state=FormSubmissionState.waiting,null!=(t=this.submitter)&&t.setAttribute("disabled",""),dispatch("turbo:submit-start",{target:this.formElement,detail:{formSubmission:this}}),this.delegate.formSubmissionStarted(this)}requestPreventedHandlingResponse(e,t){this.result={success:t.succeeded,fetchResponse:t}}requestSucceededWithResponse(e,t){t.clientError||t.serverError?this.delegate.formSubmissionFailedWithResponse(this,t):this.requestMustRedirect(e)&&responseSucceededWithoutRedirect(t)?(e=new Error("Form responses must redirect to another location"),this.delegate.formSubmissionErrored(this,e)):(this.state=FormSubmissionState.receiving,this.result={success:!0,fetchResponse:t},this.delegate.formSubmissionSucceededWithResponse(this,t))}requestFailedWithResponse(e,t){this.result={success:!1,fetchResponse:t},this.delegate.formSubmissionFailedWithResponse(this,t)}requestErrored(e,t){this.result={success:!1,error:t},this.delegate.formSubmissionErrored(this,t)}requestFinished(e){var t;this.state=FormSubmissionState.stopped,null!=(t=this.submitter)&&t.removeAttribute("disabled"),dispatch("turbo:submit-end",{target:this.formElement,detail:Object.assign({formSubmission:this},this.result)}),this.delegate.formSubmissionFinished(this)}requestMustRedirect(e){return!e.isIdempotent&&this.mustRedirect}}function buildFormData(e,t){var e=new FormData(e),s=null==t?void 0:t.getAttribute("name"),t=null==t?void 0:t.getAttribute("value");return s&&null!=t&&e.get(s)!=t&&e.append(s,t),e}function getCookieValue(t){var e;return null!=t&&(e=(document.cookie?document.cookie.split("; "):[]).find(e=>e.startsWith(t)))&&(e=e.split("=").slice(1).join("="))?decodeURIComponent(e):void 0}function getMetaContent(e){e=document.querySelector(`meta[name="${e}"]`);return e&&e.content}function responseSucceededWithoutRedirect(e){return 200==e.statusCode&&!e.redirected}function mergeFormDataEntries(e,t){var s,r,i=new URLSearchParams;for([s,r]of t)r instanceof File||i.append(s,r);return e.search=i.toString(),e}class Snapshot{constructor(e){this.element=e}get children(){return[...this.element.children]}hasAnchor(e){return null!=this.getElementForAnchor(e)}getElementForAnchor(e){return e?this.element.querySelector(`[id='${e}'], a[name='${e}']`):null}get isConnected(){return this.element.isConnected}get firstAutofocusableElement(){return this.element.querySelector("[autofocus]")}get permanentElements(){return[...this.element.querySelectorAll("[id][data-turbo-permanent]")]}getPermanentElementById(e){return this.element.querySelector(`#${e}[data-turbo-permanent]`)}getPermanentElementMapForSnapshot(e){var t={};for(const i of this.permanentElements){var s=i["id"],r=e.getPermanentElementById(s);r&&(t[s]=[i,r])}return t}}class FormInterceptor{constructor(e,t){this.submitBubbled=e=>{var t,s=e.target;!e.defaultPrevented&&s instanceof HTMLFormElement&&s.closest("turbo-frame, html")==this.element&&"dialog"!=((null==(t=e.submitter||void 0)?void 0:t.getAttribute("formmethod"))||s.method)&&this.delegate.shouldInterceptFormSubmission(s,t)&&(e.preventDefault(),e.stopImmediatePropagation(),this.delegate.formSubmissionIntercepted(s,t))},this.delegate=e,this.element=t}start(){this.element.addEventListener("submit",this.submitBubbled)}stop(){this.element.removeEventListener("submit",this.submitBubbled)}}class View{constructor(e,t){this.resolveRenderPromise=e=>{},this.resolveInterceptionPromise=e=>{},this.delegate=e,this.element=t}scrollToAnchor(e){e=this.snapshot.getElementForAnchor(e);e?(this.scrollToElement(e),this.focusElement(e)):this.scrollToPosition({x:0,y:0})}scrollToAnchorFromLocation(e){this.scrollToAnchor(getAnchor(e))}scrollToElement(e){e.scrollIntoView()}focusElement(e){e instanceof HTMLElement&&(e.hasAttribute("tabindex")?e.focus():(e.setAttribute("tabindex","-1"),e.focus(),e.removeAttribute("tabindex")))}scrollToPosition({x:e,y:t}){this.scrollRoot.scrollTo(e,t)}scrollToTop(){this.scrollToPosition({x:0,y:0})}get scrollRoot(){return window}async render(e){var{isPreview:t,shouldRender:s,newSnapshot:r}=e;if(s)try{this.renderPromise=new Promise(e=>this.resolveRenderPromise=e),this.renderer=e,this.prepareToRenderSnapshot(e);var i=new Promise(e=>this.resolveInterceptionPromise=e);this.delegate.allowsImmediateRender(r,this.resolveInterceptionPromise)||await i,await this.renderSnapshot(e),this.delegate.viewRenderedSnapshot(r,t),this.finishRenderingSnapshot(e)}finally{delete this.renderer,this.resolveRenderPromise(void 0),delete this.renderPromise}else this.invalidate()}invalidate(){this.delegate.viewInvalidated()}prepareToRenderSnapshot(e){this.markAsPreview(e.isPreview),e.prepareToRender()}markAsPreview(e){e?this.element.setAttribute("data-turbo-preview",""):this.element.removeAttribute("data-turbo-preview")}async renderSnapshot(e){await e.render()}finishRenderingSnapshot(e){e.finishRendering()}}class FrameView extends View{invalidate(){this.element.innerHTML=""}get snapshot(){return new Snapshot(this.element)}}class LinkInterceptor{constructor(e,t){this.clickBubbled=e=>{this.respondsToEventTarget(e.target)?this.clickEvent=e:delete this.clickEvent},this.linkClicked=e=>{this.clickEvent&&this.respondsToEventTarget(e.target)&&e.target instanceof Element&&this.delegate.shouldInterceptLinkClick(e.target,e.detail.url)&&(this.clickEvent.preventDefault(),e.preventDefault(),this.delegate.linkClickIntercepted(e.target,e.detail.url)),delete this.clickEvent},this.willVisit=()=>{delete this.clickEvent},this.delegate=e,this.element=t}start(){this.element.addEventListener("click",this.clickBubbled),document.addEventListener("turbo:click",this.linkClicked),document.addEventListener("turbo:before-visit",this.willVisit)}stop(){this.element.removeEventListener("click",this.clickBubbled),document.removeEventListener("turbo:click",this.linkClicked),document.removeEventListener("turbo:before-visit",this.willVisit)}respondsToEventTarget(e){e=e instanceof Element?e:e instanceof Node?e.parentElement:null;return e&&e.closest("turbo-frame, html")==this.element}}class Bardo{constructor(e){this.permanentElementMap=e}static preservingPermanentElements(e,t){e=new this(e);e.enter(),t(),e.leave()}enter(){for(const t in this.permanentElementMap){var[,e]=this.permanentElementMap[t];this.replaceNewPermanentElementWithPlaceholder(e)}}leave(){for(const t in this.permanentElementMap){var[e]=this.permanentElementMap[t];this.replaceCurrentPermanentElementWithClone(e),this.replacePlaceholderWithPermanentElement(e)}}replaceNewPermanentElementWithPlaceholder(e){var t=createPlaceholderForPermanentElement(e);e.replaceWith(t)}replaceCurrentPermanentElementWithClone(e){var t=e.cloneNode(!0);e.replaceWith(t)}replacePlaceholderWithPermanentElement(e){var t=this.getPlaceholderById(e.id);null!=t&&t.replaceWith(e)}getPlaceholderById(t){return this.placeholders.find(e=>e.content==t)}get placeholders(){return[...document.querySelectorAll("meta[name=turbo-permanent-placeholder][content]")]}}function createPlaceholderForPermanentElement(e){var t=document.createElement("meta");return t.setAttribute("name","turbo-permanent-placeholder"),t.setAttribute("content",e.id),t}class Renderer{constructor(e,t,s,r=!0){this.currentSnapshot=e,this.newSnapshot=t,this.isPreview=s,this.willRender=r,this.promise=new Promise((e,t)=>this.resolvingFunctions={resolve:e,reject:t})}get shouldRender(){return!0}prepareToRender(){}finishRendering(){this.resolvingFunctions&&(this.resolvingFunctions.resolve(),delete this.resolvingFunctions)}createScriptElement(e){var t;return"false"==e.getAttribute("data-turbo-eval")?e:(t=document.createElement("script"),this.cspNonce&&(t.nonce=this.cspNonce),t.textContent=e.textContent,t.async=!1,copyElementAttributes(t,e),t)}preservingPermanentElements(e){Bardo.preservingPermanentElements(this.permanentElementMap,e)}focusFirstAutofocusableElement(){var e=this.connectedSnapshot.firstAutofocusableElement;elementIsFocusable(e)&&e.focus()}get connectedSnapshot(){return this.newSnapshot.isConnected?this.newSnapshot:this.currentSnapshot}get currentElement(){return this.currentSnapshot.element}get newElement(){return this.newSnapshot.element}get permanentElementMap(){return this.currentSnapshot.getPermanentElementMapForSnapshot(this.newSnapshot)}get cspNonce(){var e;return null==(e=document.head.querySelector('meta[name="csp-nonce"]'))?void 0:e.getAttribute("content")}}function copyElementAttributes(e,t){for(var{name:s,value:r}of[...t.attributes])e.setAttribute(s,r)}function elementIsFocusable(e){return e&&"function"==typeof e.focus}class FrameRenderer extends Renderer{get shouldRender(){return!0}async render(){await nextAnimationFrame(),this.preservingPermanentElements(()=>{this.loadFrameElement()}),this.scrollFrameIntoView(),await nextAnimationFrame(),this.focusFirstAutofocusableElement(),await nextAnimationFrame(),this.activateScriptElements()}loadFrameElement(){var e=document.createRange(),e=(e.selectNodeContents(this.currentElement),e.deleteContents(),this.newElement),t=null==(t=e.ownerDocument)?void 0:t.createRange();t&&(t.selectNodeContents(e),this.currentElement.appendChild(t.extractContents()))}scrollFrameIntoView(){if(this.currentElement.autoscroll||this.newElement.autoscroll){var e=this.currentElement.firstElementChild,t=readScrollLogicalPosition(this.currentElement.getAttribute("data-autoscroll-block"),"end");if(e)return e.scrollIntoView({block:t}),!0}return!1}activateScriptElements(){for(const t of this.newScriptElements){var e=this.createScriptElement(t);t.replaceWith(e)}}get newScriptElements(){return this.currentElement.querySelectorAll("script")}}function readScrollLogicalPosition(e,t){return"end"==e||"start"==e||"center"==e||"nearest"==e?e:t}class ProgressBar{constructor(){this.hiding=!1,this.value=0,this.visible=!1,this.trickle=()=>{this.setValue(this.value+Math.random()/100)},this.stylesheetElement=this.createStylesheetElement(),this.progressElement=this.createProgressElement(),this.installStylesheetElement(),this.setValue(0)}static get defaultCSS(){return unindent`
+ .turbo-progress-bar {
+ position: fixed;
+ display: block;
+ top: 0;
+ left: 0;
+ height: 3px;
+ background: #0076ff;
+ z-index: 9999;
+ transition:
+ width ${ProgressBar.animationDuration}ms ease-out,
+ opacity ${ProgressBar.animationDuration/2}ms ${ProgressBar.animationDuration/2}ms ease-in;
+ transform: translate3d(0, 0, 0);
+ }
+ `}show(){this.visible||(this.visible=!0,this.installProgressElement(),this.startTrickling())}hide(){this.visible&&!this.hiding&&(this.hiding=!0,this.fadeProgressElement(()=>{this.uninstallProgressElement(),this.stopTrickling(),this.visible=!1,this.hiding=!1}))}setValue(e){this.value=e,this.refresh()}installStylesheetElement(){document.head.insertBefore(this.stylesheetElement,document.head.firstChild)}installProgressElement(){this.progressElement.style.width="0",this.progressElement.style.opacity="1",document.documentElement.insertBefore(this.progressElement,document.body),this.refresh()}fadeProgressElement(e){this.progressElement.style.opacity="0",setTimeout(e,1.5*ProgressBar.animationDuration)}uninstallProgressElement(){this.progressElement.parentNode&&document.documentElement.removeChild(this.progressElement)}startTrickling(){this.trickleInterval||(this.trickleInterval=window.setInterval(this.trickle,ProgressBar.animationDuration))}stopTrickling(){window.clearInterval(this.trickleInterval),delete this.trickleInterval}refresh(){requestAnimationFrame(()=>{this.progressElement.style.width=10+90*this.value+"%"})}createStylesheetElement(){var e=document.createElement("style");return e.type="text/css",e.textContent=ProgressBar.defaultCSS,e}createProgressElement(){var e=document.createElement("div");return e.className="turbo-progress-bar",e}}ProgressBar.animationDuration=300;class HeadSnapshot extends Snapshot{constructor(){super(...arguments),this.detailsByOuterHTML=this.children.filter(e=>!elementIsNoscript(e)).map(e=>elementWithoutNonce(e)).reduce((e,t)=>{var s=t["outerHTML"],r=s in e?e[s]:{type:elementType(t),tracked:elementIsTracked(t),elements:[]};return Object.assign(Object.assign({},e),{[s]:Object.assign(Object.assign({},r),{elements:[...r.elements,t]})})},{})}get trackedElementSignature(){return Object.keys(this.detailsByOuterHTML).filter(e=>this.detailsByOuterHTML[e].tracked).join("")}getScriptElementsNotInSnapshot(e){return this.getElementsMatchingTypeNotInSnapshot("script",e)}getStylesheetElementsNotInSnapshot(e){return this.getElementsMatchingTypeNotInSnapshot("stylesheet",e)}getElementsMatchingTypeNotInSnapshot(t,s){return Object.keys(this.detailsByOuterHTML).filter(e=>!(e in s.detailsByOuterHTML)).map(e=>this.detailsByOuterHTML[e]).filter(({type:e})=>e==t).map(({elements:[e]})=>e)}get provisionalElements(){return Object.keys(this.detailsByOuterHTML).reduce((e,t)=>{var{type:t,tracked:s,elements:r}=this.detailsByOuterHTML[t];return null!=t||s?1{var[t]=this.detailsByOuterHTML[t]["elements"];return elementIsMetaElementWithName(t,s)?t:e},void 0)}}function elementType(e){return elementIsScript(e)?"script":elementIsStylesheet(e)?"stylesheet":void 0}function elementIsTracked(e){return"reload"==e.getAttribute("data-turbo-track")}function elementIsScript(e){return"script"==e.tagName.toLowerCase()}function elementIsNoscript(e){return"noscript"==e.tagName.toLowerCase()}function elementIsStylesheet(e){var t=e.tagName.toLowerCase();return"style"==t||"link"==t&&"stylesheet"==e.getAttribute("rel")}function elementIsMetaElementWithName(e,t){return"meta"==e.tagName.toLowerCase()&&e.getAttribute("name")==t}function elementWithoutNonce(e){return e.hasAttribute("nonce")&&e.setAttribute("nonce",""),e}class PageSnapshot extends Snapshot{constructor(e,t){super(e),this.headSnapshot=t}static fromHTMLString(e=""){return this.fromDocument(parseHTMLDocument(e))}static fromElement(e){return this.fromDocument(e.ownerDocument)}static fromDocument({head:e,body:t}){return new this(t,new HeadSnapshot(e))}clone(){return new PageSnapshot(this.element.cloneNode(!0),this.headSnapshot)}get headElement(){return this.headSnapshot.element}get rootLocation(){var e;return expandURL(null!=(e=this.getSetting("root"))?e:"/")}get cacheControlValue(){return this.getSetting("cache-control")}get isPreviewable(){return"no-preview"!=this.cacheControlValue}get isCacheable(){return"no-cache"!=this.cacheControlValue}get isVisitable(){return"reload"!=this.getSetting("visit-control")}getSetting(e){return this.headSnapshot.getMetaValue("turbo-"+e)}}!function(e){e.visitStart="visitStart",e.requestStart="requestStart",e.requestEnd="requestEnd",e.visitEnd="visitEnd"}(TimingMetric=TimingMetric||{}),function(e){e.initialized="initialized",e.started="started",e.canceled="canceled",e.failed="failed",e.completed="completed"}(VisitState=VisitState||{});const defaultOptions={action:"advance",historyChanged:!1,visitCachedSnapshot:()=>{},willRender:!0};!function(e){e[e.networkFailure=0]="networkFailure",e[e.timeoutFailure=-1]="timeoutFailure",e[e.contentTypeMismatch=-2]="contentTypeMismatch"}(SystemStatusCode=SystemStatusCode||{});class Visit{constructor(e,t,s,r={}){this.identifier=uuid(),this.timingMetrics={},this.followedRedirect=!1,this.historyChanged=!1,this.scrolled=!1,this.snapshotCached=!1,this.state=VisitState.initialized,this.delegate=e,this.location=t,this.restorationIdentifier=s||uuid();var{action:e,historyChanged:t,referrer:s,snapshotHTML:r,response:i,visitCachedSnapshot:n,willRender:o}=Object.assign(Object.assign({},defaultOptions),r);this.action=e,this.historyChanged=t,this.referrer=s,this.snapshotHTML=r,this.response=i,this.isSamePage=this.delegate.locationWithActionIsSamePage(this.location,this.action),this.visitCachedSnapshot=n,this.willRender=o,this.scrolled=!o}get adapter(){return this.delegate.adapter}get view(){return this.delegate.view}get history(){return this.delegate.history}get restorationData(){return this.history.getRestorationDataForIdentifier(this.restorationIdentifier)}get silent(){return this.isSamePage}start(){this.state==VisitState.initialized&&(this.recordTimingMetric(TimingMetric.visitStart),this.state=VisitState.started,this.adapter.visitStarted(this),this.delegate.visitStarted(this))}cancel(){this.state==VisitState.started&&(this.request&&this.request.cancel(),this.cancelRender(),this.state=VisitState.canceled)}complete(){this.state==VisitState.started&&(this.recordTimingMetric(TimingMetric.visitEnd),this.state=VisitState.completed,this.adapter.visitCompleted(this),this.delegate.visitCompleted(this),this.followRedirect())}fail(){this.state==VisitState.started&&(this.state=VisitState.failed,this.adapter.visitFailed(this))}changeHistory(){var e;this.historyChanged||(e=this.location.href===(null==(e=this.referrer)?void 0:e.href)?"replace":this.action,e=this.getHistoryMethodForAction(e),this.history.update(e,this.location,this.restorationIdentifier),this.historyChanged=!0)}issueRequest(){this.hasPreloadedResponse()?this.simulateRequest():this.shouldIssueRequest()&&!this.request&&(this.request=new FetchRequest(this,FetchMethod.get,this.location),this.request.perform())}simulateRequest(){this.response&&(this.startRequest(),this.recordResponse(),this.finishRequest())}startRequest(){this.recordTimingMetric(TimingMetric.requestStart),this.adapter.visitRequestStarted(this)}recordResponse(e=this.response){(this.response=e)&&(e=e["statusCode"],isSuccessful(e)?this.adapter.visitRequestCompleted(this):this.adapter.visitRequestFailedWithStatusCode(this,e))}finishRequest(){this.recordTimingMetric(TimingMetric.requestEnd),this.adapter.visitRequestFinished(this)}loadResponse(){if(this.response){const{statusCode:e,responseHTML:t}=this.response;this.render(async()=>{this.cacheSnapshot(),this.view.renderPromise&&await this.view.renderPromise,isSuccessful(e)&&null!=t?(await this.view.renderPage(PageSnapshot.fromHTMLString(t),!1,this.willRender),this.adapter.visitRendered(this),this.complete()):(await this.view.renderError(PageSnapshot.fromHTMLString(t)),this.adapter.visitRendered(this),this.fail())})}}getCachedSnapshot(){var e=this.view.getCachedSnapshotForLocation(this.location)||this.getPreloadedSnapshot();if(e&&(!getAnchor(this.location)||e.hasAnchor(getAnchor(this.location)))&&("restore"==this.action||e.isPreviewable))return e}getPreloadedSnapshot(){if(this.snapshotHTML)return PageSnapshot.fromHTMLString(this.snapshotHTML)}hasCachedSnapshot(){return null!=this.getCachedSnapshot()}loadCachedSnapshot(){const e=this.getCachedSnapshot();if(e){const t=this.shouldIssueRequest();this.render(async()=>{this.cacheSnapshot(),this.isSamePage?this.adapter.visitRendered(this):(this.view.renderPromise&&await this.view.renderPromise,await this.view.renderPage(e,t,this.willRender),this.adapter.visitRendered(this),t||this.complete())})}}followRedirect(){var e;this.redirectedToLocation&&!this.followedRedirect&&null!=(e=this.response)&&e.redirected&&(this.adapter.visitProposedToLocation(this.redirectedToLocation,{action:"replace",response:this.response}),this.followedRedirect=!0)}goToSamePageAnchor(){this.isSamePage&&this.render(async()=>{this.cacheSnapshot(),this.adapter.visitRendered(this)})}requestStarted(){this.startRequest()}requestPreventedHandlingResponse(e,t){}async requestSucceededWithResponse(e,t){var s=await t.responseHTML,{redirected:r,statusCode:i}=t;null==s?this.recordResponse({statusCode:SystemStatusCode.contentTypeMismatch,redirected:r}):(this.redirectedToLocation=t.redirected?t.location:void 0,this.recordResponse({statusCode:i,responseHTML:s,redirected:r}))}async requestFailedWithResponse(e,t){var s=await t.responseHTML,{redirected:t,statusCode:r}=t;null==s?this.recordResponse({statusCode:SystemStatusCode.contentTypeMismatch,redirected:t}):this.recordResponse({statusCode:r,responseHTML:s,redirected:t})}requestErrored(e,t){this.recordResponse({statusCode:SystemStatusCode.networkFailure,redirected:!1})}requestFinished(){this.finishRequest()}performScroll(){this.scrolled||("restore"==this.action?this.scrollToRestoredPosition()||this.scrollToAnchor()||this.view.scrollToTop():this.scrollToAnchor()||this.view.scrollToTop(),this.isSamePage&&this.delegate.visitScrolledToSamePageLocation(this.view.lastRenderedLocation,this.location),this.scrolled=!0)}scrollToRestoredPosition(){var e=this.restorationData["scrollPosition"];if(e)return this.view.scrollToPosition(e),!0}scrollToAnchor(){var e=getAnchor(this.location);if(null!=e)return this.view.scrollToAnchor(e),!0}recordTimingMetric(e){this.timingMetrics[e]=(new Date).getTime()}getTimingMetrics(){return Object.assign({},this.timingMetrics)}getHistoryMethodForAction(e){switch(e){case"replace":return history.replaceState;case"advance":case"restore":return history.pushState}}hasPreloadedResponse(){return"object"==typeof this.response}shouldIssueRequest(){return!this.isSamePage&&("restore"==this.action?!this.hasCachedSnapshot():this.willRender)}cacheSnapshot(){this.snapshotCached||(this.view.cacheSnapshot().then(e=>e&&this.visitCachedSnapshot(e)),this.snapshotCached=!0)}async render(e){this.cancelRender(),await new Promise(e=>{this.frame=requestAnimationFrame(()=>e())}),await e(),delete this.frame,this.performScroll()}cancelRender(){this.frame&&(cancelAnimationFrame(this.frame),delete this.frame)}}function isSuccessful(e){return 200<=e&&e<300}class BrowserAdapter{constructor(e){this.progressBar=new ProgressBar,this.showProgressBar=()=>{this.progressBar.show()},this.session=e}visitProposedToLocation(e,t){this.navigator.startVisit(e,uuid(),t)}visitStarted(e){e.loadCachedSnapshot(),e.issueRequest(),e.changeHistory(),e.goToSamePageAnchor()}visitRequestStarted(e){this.progressBar.setValue(0),e.hasCachedSnapshot()||"restore"!=e.action?this.showVisitProgressBarAfterDelay():this.showProgressBar()}visitRequestCompleted(e){e.loadResponse()}visitRequestFailedWithStatusCode(e,t){switch(t){case SystemStatusCode.networkFailure:case SystemStatusCode.timeoutFailure:case SystemStatusCode.contentTypeMismatch:return this.reload();default:return e.loadResponse()}}visitRequestFinished(e){this.progressBar.setValue(1),this.hideVisitProgressBar()}visitCompleted(e){}pageInvalidated(){this.reload()}visitFailed(e){}visitRendered(e){}formSubmissionStarted(e){this.progressBar.setValue(0),this.showFormProgressBarAfterDelay()}formSubmissionFinished(e){this.progressBar.setValue(1),this.hideFormProgressBar()}showVisitProgressBarAfterDelay(){this.visitProgressBarTimeout=window.setTimeout(this.showProgressBar,this.session.progressBarDelay)}hideVisitProgressBar(){this.progressBar.hide(),null!=this.visitProgressBarTimeout&&(window.clearTimeout(this.visitProgressBarTimeout),delete this.visitProgressBarTimeout)}showFormProgressBarAfterDelay(){null==this.formProgressBarTimeout&&(this.formProgressBarTimeout=window.setTimeout(this.showProgressBar,this.session.progressBarDelay))}hideFormProgressBar(){this.progressBar.hide(),null!=this.formProgressBarTimeout&&(window.clearTimeout(this.formProgressBarTimeout),delete this.formProgressBarTimeout)}reload(){window.location.reload()}get navigator(){return this.session.navigator}}class CacheObserver{constructor(){this.started=!1}start(){this.started||(this.started=!0,addEventListener("turbo:before-cache",this.removeStaleElements,!1))}stop(){this.started&&(this.started=!1,removeEventListener("turbo:before-cache",this.removeStaleElements,!1))}removeStaleElements(){for(const e of[...document.querySelectorAll('[data-turbo-cache="false"]')])e.remove()}}class FormSubmitObserver{constructor(e){this.started=!1,this.submitCaptured=()=>{removeEventListener("submit",this.submitBubbled,!1),addEventListener("submit",this.submitBubbled,!1)},this.submitBubbled=e=>{var t,s;e.defaultPrevented||(t=e.target instanceof HTMLFormElement?e.target:void 0,s=e.submitter||void 0,t&&"dialog"!=((null==s?void 0:s.getAttribute("formmethod"))||t.getAttribute("method"))&&this.delegate.willSubmitForm(t,s)&&(e.preventDefault(),this.delegate.formSubmitted(t,s)))},this.delegate=e}start(){this.started||(addEventListener("submit",this.submitCaptured,!0),this.started=!0)}stop(){this.started&&(removeEventListener("submit",this.submitCaptured,!0),this.started=!1)}}class FrameRedirector{constructor(e){this.element=e,this.linkInterceptor=new LinkInterceptor(this,e),this.formInterceptor=new FormInterceptor(this,e)}start(){this.linkInterceptor.start(),this.formInterceptor.start()}stop(){this.linkInterceptor.stop(),this.formInterceptor.stop()}shouldInterceptLinkClick(e,t){return this.shouldRedirect(e)}linkClickIntercepted(e,t){var s=this.findFrameElement(e);s&&s.delegate.linkClickIntercepted(e,t)}shouldInterceptFormSubmission(e,t){return this.shouldSubmit(e,t)}formSubmissionIntercepted(e,t){var s=this.findFrameElement(e,t);s&&(s.removeAttribute("reloadable"),s.delegate.formSubmissionIntercepted(e,t))}shouldSubmit(e,t){var s=getAction(e,t),r=this.element.ownerDocument.querySelector('meta[name="turbo-root"]'),r=expandURL(null!=(r=null==r?void 0:r.content)?r:"/");return this.shouldRedirect(e,t)&&locationIsVisitable(s,r)}shouldRedirect(e,t){t=this.findFrameElement(e,t);return!!t&&t!=e.closest("turbo-frame")}findFrameElement(e,t){t=(null==t?void 0:t.getAttribute("data-turbo-frame"))||e.getAttribute("data-turbo-frame");if(t&&"_top"!=t){e=this.element.querySelector(`#${t}:not([disabled])`);if(e instanceof FrameElement)return e}}}class History{constructor(e){this.restorationIdentifier=uuid(),this.restorationData={},this.started=!1,this.pageLoaded=!1,this.onPopState=e=>{this.shouldHandlePopState()&&(e=(e.state||{})["turbo"],e)&&(this.location=new URL(window.location.href),e=e["restorationIdentifier"],this.restorationIdentifier=e,this.delegate.historyPoppedToLocationWithRestorationIdentifier(this.location,e))},this.onPageLoad=async e=>{await nextMicrotask(),this.pageLoaded=!0},this.delegate=e}start(){this.started||(addEventListener("popstate",this.onPopState,!1),addEventListener("load",this.onPageLoad,!1),this.started=!0,this.replace(new URL(window.location.href)))}stop(){this.started&&(removeEventListener("popstate",this.onPopState,!1),removeEventListener("load",this.onPageLoad,!1),this.started=!1)}push(e,t){this.update(history.pushState,e,t)}replace(e,t){this.update(history.replaceState,e,t)}update(e,t,s=uuid()){e.call(history,{turbo:{restorationIdentifier:s}},"",t.href),this.location=t,this.restorationIdentifier=s}getRestorationDataForIdentifier(e){return this.restorationData[e]||{}}updateRestorationData(e){var t=this["restorationIdentifier"],s=this.restorationData[t];this.restorationData[t]=Object.assign(Object.assign({},s),e)}assumeControlOfScrollRestoration(){var e;this.previousScrollRestoration||(this.previousScrollRestoration=null!=(e=history.scrollRestoration)?e:"auto",history.scrollRestoration="manual")}relinquishControlOfScrollRestoration(){this.previousScrollRestoration&&(history.scrollRestoration=this.previousScrollRestoration,delete this.previousScrollRestoration)}shouldHandlePopState(){return this.pageIsLoaded()}pageIsLoaded(){return this.pageLoaded||"complete"==document.readyState}}class LinkClickObserver{constructor(e){this.started=!1,this.clickCaptured=()=>{removeEventListener("click",this.clickBubbled,!1),addEventListener("click",this.clickBubbled,!1)},this.clickBubbled=e=>{var t,s;this.clickEventIsSignificant(e)&&(t=e.composedPath&&e.composedPath()[0]||e.target,t=this.findLinkFromClickTarget(t))&&(s=this.getLocationForLink(t),this.delegate.willFollowLinkToLocation(t,s))&&(e.preventDefault(),this.delegate.followedLinkToLocation(t,s))},this.delegate=e}start(){this.started||(addEventListener("click",this.clickCaptured,!0),this.started=!0)}stop(){this.started&&(removeEventListener("click",this.clickCaptured,!0),this.started=!1)}clickEventIsSignificant(e){return!(e.target&&e.target.isContentEditable||e.defaultPrevented||1{var e=this["readyState"];"interactive"==e?this.pageIsInteractive():"complete"==e&&this.pageIsComplete()},this.pageWillUnload=()=>{this.delegate.pageWillUnload()},this.delegate=e}start(){this.started||(this.stage==PageStage.initial&&(this.stage=PageStage.loading),document.addEventListener("readystatechange",this.interpretReadyState,!1),addEventListener("pagehide",this.pageWillUnload,!1),this.started=!0)}stop(){this.started&&(document.removeEventListener("readystatechange",this.interpretReadyState,!1),removeEventListener("pagehide",this.pageWillUnload,!1),this.started=!1)}pageIsInteractive(){this.stage==PageStage.loading&&(this.stage=PageStage.interactive,this.delegate.pageBecameInteractive())}pageIsComplete(){this.pageIsInteractive(),this.stage==PageStage.interactive&&(this.stage=PageStage.complete,this.delegate.pageLoaded())}get readyState(){return document.readyState}}class ScrollObserver{constructor(e){this.started=!1,this.onScroll=()=>{this.updatePosition({x:window.pageXOffset,y:window.pageYOffset})},this.delegate=e}start(){this.started||(addEventListener("scroll",this.onScroll,!1),this.onScroll(),this.started=!0)}stop(){this.started&&(removeEventListener("scroll",this.onScroll,!1),this.started=!1)}updatePosition(e){this.delegate.scrollPositionChanged(e)}}class StreamObserver{constructor(e){this.sources=new Set,this.started=!1,this.inspectFetchResponse=e=>{var t=fetchResponseFromEvent(e);t&&fetchResponseIsStream(t)&&(e.preventDefault(),this.receiveMessageResponse(t))},this.receiveMessageEvent=e=>{this.started&&"string"==typeof e.data&&this.receiveMessageHTML(e.data)},this.delegate=e}start(){this.started||(this.started=!0,addEventListener("turbo:before-fetch-response",this.inspectFetchResponse,!1))}stop(){this.started&&(this.started=!1,removeEventListener("turbo:before-fetch-response",this.inspectFetchResponse,!1))}connectStreamSource(e){this.streamSourceIsConnected(e)||(this.sources.add(e),e.addEventListener("message",this.receiveMessageEvent,!1))}disconnectStreamSource(e){this.streamSourceIsConnected(e)&&(this.sources.delete(e),e.removeEventListener("message",this.receiveMessageEvent,!1))}streamSourceIsConnected(e){return this.sources.has(e)}async receiveMessageResponse(e){e=await e.responseHTML;e&&this.receiveMessageHTML(e)}receiveMessageHTML(e){this.delegate.receivedMessageFromStream(new StreamMessage(e))}}function fetchResponseFromEvent(e){e=null==(e=e.detail)?void 0:e.fetchResponse;if(e instanceof FetchResponse)return e}function fetchResponseIsStream(e){return(null!=(e=e.contentType)?e:"").startsWith(StreamMessage.contentType)}class ErrorRenderer extends Renderer{async render(){this.replaceHeadAndBody(),this.activateScriptElements()}replaceHeadAndBody(){var{documentElement:e,head:t,body:s}=document;e.replaceChild(this.newHead,t),e.replaceChild(this.newElement,s)}activateScriptElements(){for(const s of this.scriptElements){var e,t=s.parentNode;t&&(e=this.createScriptElement(s),t.replaceChild(e,s))}}get newHead(){return this.newSnapshot.headSnapshot.element}get scriptElements(){return[...document.documentElement.querySelectorAll("script")]}}class PageRenderer extends Renderer{get shouldRender(){return this.newSnapshot.isVisitable&&this.trackedElementsAreIdentical}prepareToRender(){this.mergeHead()}async render(){this.willRender&&this.replaceBody()}finishRendering(){super.finishRendering(),this.isPreview||this.focusFirstAutofocusableElement()}get currentHeadSnapshot(){return this.currentSnapshot.headSnapshot}get newHeadSnapshot(){return this.newSnapshot.headSnapshot}get newElement(){return this.newSnapshot.element}mergeHead(){this.copyNewHeadStylesheetElements(),this.copyNewHeadScriptElements(),this.removeCurrentHeadProvisionalElements(),this.copyNewHeadProvisionalElements()}replaceBody(){this.preservingPermanentElements(()=>{this.activateNewBody(),this.assignNewBody()})}get trackedElementsAreIdentical(){return this.currentHeadSnapshot.trackedElementSignature==this.newHeadSnapshot.trackedElementSignature}copyNewHeadStylesheetElements(){for(const e of this.newHeadStylesheetElements)document.head.appendChild(e)}copyNewHeadScriptElements(){for(const e of this.newHeadScriptElements)document.head.appendChild(this.createScriptElement(e))}removeCurrentHeadProvisionalElements(){for(const e of this.currentHeadProvisionalElements)document.head.removeChild(e)}copyNewHeadProvisionalElements(){for(const e of this.newHeadProvisionalElements)document.head.appendChild(e)}activateNewBody(){document.adoptNode(this.newElement),this.activateNewBodyScriptElements()}activateNewBodyScriptElements(){for(const t of this.newBodyScriptElements){var e=this.createScriptElement(t);t.replaceWith(e)}}assignNewBody(){document.body&&this.newElement instanceof HTMLBodyElement?document.body.replaceWith(this.newElement):document.documentElement.appendChild(this.newElement)}get newHeadStylesheetElements(){return this.newHeadSnapshot.getStylesheetElementsNotInSnapshot(this.currentHeadSnapshot)}get newHeadScriptElements(){return this.newHeadSnapshot.getScriptElementsNotInSnapshot(this.currentHeadSnapshot)}get currentHeadProvisionalElements(){return this.currentHeadSnapshot.provisionalElements}get newHeadProvisionalElements(){return this.newHeadSnapshot.provisionalElements}get newBodyScriptElements(){return this.newElement.querySelectorAll("script")}}class SnapshotCache{constructor(e){this.keys=[],this.snapshots={},this.size=e}has(e){return toCacheKey(e)in this.snapshots}get(e){var t;if(this.has(e))return t=this.read(e),this.touch(e),t}put(e,t){return this.write(e,t),this.touch(e),t}clear(){this.snapshots={}}read(e){return this.snapshots[toCacheKey(e)]}write(e,t){this.snapshots[toCacheKey(e)]=t}touch(e){var e=toCacheKey(e),t=this.keys.indexOf(e);-1s.remove())):s.addEventListener("submit",()=>s.remove()),document.body.appendChild(s),dispatch("submit",{cancelable:!0,target:s})}return!1}allowsVisitingLocationWithAction(e,t){return this.locationWithActionIsSamePage(e,t)||this.applicationAllowsVisitingLocation(e)}visitProposedToLocation(e,t){extendURLWithDeprecatedProperties(e),this.adapter.visitProposedToLocation(e,t)}visitStarted(e){extendURLWithDeprecatedProperties(e.location),e.silent||this.notifyApplicationAfterVisitingLocation(e.location,e.action)}visitCompleted(e){this.notifyApplicationAfterPageLoad(e.getTimingMetrics())}locationWithActionIsSamePage(e,t){return this.navigator.locationWithActionIsSamePage(e,t)}visitScrolledToSamePageLocation(e,t){this.notifyApplicationAfterVisitingSamePageLocation(e,t)}willSubmitForm(e,t){var s=getAction(e,t);return this.elementDriveEnabled(e)&&(!t||this.elementDriveEnabled(t))&&locationIsVisitable(expandURL(s),this.snapshot.rootLocation)}formSubmitted(e,t){this.navigator.submitForm(e,t)}pageBecameInteractive(){this.view.lastRenderedLocation=this.location,this.notifyApplicationAfterPageLoad()}pageLoaded(){this.history.assumeControlOfScrollRestoration()}pageWillUnload(){this.history.relinquishControlOfScrollRestoration()}receivedMessageFromStream(e){this.renderStreamMessage(e)}viewWillCacheSnapshot(){var e;null!=(e=this.navigator.currentVisit)&&e.silent||this.notifyApplicationBeforeCachingSnapshot()}allowsImmediateRender({element:e},t){return!this.notifyApplicationBeforeRender(e,t).defaultPrevented}viewRenderedSnapshot(e,t){this.view.lastRenderedLocation=this.history.location,this.notifyApplicationAfterRender()}viewInvalidated(){this.adapter.pageInvalidated()}frameLoaded(e){this.notifyApplicationAfterFrameLoad(e)}frameRendered(e,t){this.notifyApplicationAfterFrameRender(e,t)}applicationAllowsFollowingLinkToLocation(e,t){return!this.notifyApplicationAfterClickingLinkToLocation(e,t).defaultPrevented}applicationAllowsVisitingLocation(e){return!this.notifyApplicationBeforeVisitingLocation(e).defaultPrevented}notifyApplicationAfterClickingLinkToLocation(e,t){return dispatch("turbo:click",{target:e,detail:{url:t.href},cancelable:!0})}notifyApplicationBeforeVisitingLocation(e){return dispatch("turbo:before-visit",{detail:{url:e.href},cancelable:!0})}notifyApplicationAfterVisitingLocation(e,t){return markAsBusy(document.documentElement),dispatch("turbo:visit",{detail:{url:e.href,action:t}})}notifyApplicationBeforeCachingSnapshot(){return dispatch("turbo:before-cache")}notifyApplicationBeforeRender(e,t){return dispatch("turbo:before-render",{detail:{newBody:e,resume:t},cancelable:!0})}notifyApplicationAfterRender(){return dispatch("turbo:render")}notifyApplicationAfterPageLoad(e={}){return clearBusyState(document.documentElement),dispatch("turbo:load",{detail:{url:this.location.href,timing:e}})}notifyApplicationAfterVisitingSamePageLocation(e,t){dispatchEvent(new HashChangeEvent("hashchange",{oldURL:e.toString(),newURL:t.toString()}))}notifyApplicationAfterFrameLoad(e){return dispatch("turbo:frame-load",{target:e})}notifyApplicationAfterFrameRender(e,t){return dispatch("turbo:frame-render",{detail:{fetchResponse:e},target:t,cancelable:!0})}elementDriveEnabled(e){e=null==e?void 0:e.closest("[data-turbo]");return this.drive?!e||"false"!=e.getAttribute("data-turbo"):!!e&&"true"==e.getAttribute("data-turbo")}getActionForLink(e){e=e.getAttribute("data-turbo-action");return isAction(e)?e:"advance"}getTargetFrameForLink(e){var t=e.getAttribute("data-turbo-frame");return t||((t=e.closest("turbo-frame"))?t.id:void 0)}get snapshot(){return this.view.snapshot}}function extendURLWithDeprecatedProperties(e){Object.defineProperties(e,deprecatedLocationPropertyDescriptors)}const deprecatedLocationPropertyDescriptors={absoluteURL:{get(){return this.toString()}}},session=new Session,navigator$1=session["navigator"];function start(){session.start()}function registerAdapter(e){session.registerAdapter(e)}function visit(e,t){session.visit(e,t)}function connectStreamSource(e){session.connectStreamSource(e)}function disconnectStreamSource(e){session.disconnectStreamSource(e)}function renderStreamMessage(e){session.renderStreamMessage(e)}function clearCache(){session.clearCache()}function setProgressBarDelay(e){session.setProgressBarDelay(e)}function setConfirmMethod(e){FormSubmission.confirmMethod=e}var Turbo=Object.freeze({__proto__:null,navigator:navigator$1,session:session,PageRenderer:PageRenderer,PageSnapshot:PageSnapshot,start:start,registerAdapter:registerAdapter,visit:visit,connectStreamSource:connectStreamSource,disconnectStreamSource:disconnectStreamSource,renderStreamMessage:renderStreamMessage,clearCache:clearCache,setProgressBarDelay:setProgressBarDelay,setConfirmMethod:setConfirmMethod});class FrameController{constructor(e){this.fetchResponseLoaded=e=>{},this.currentFetchRequest=null,this.resolveVisitPromise=()=>{},this.connected=!1,this.hasBeenLoaded=!1,this.settingSourceURL=!1,this.element=e,this.view=new FrameView(this,this.element),this.appearanceObserver=new AppearanceObserver(this,this.element),this.linkInterceptor=new LinkInterceptor(this,this.element),this.formInterceptor=new FormInterceptor(this,this.element)}connect(){this.connected||(this.connected=!0,this.reloadable=!1,this.loadingStyle==FrameLoadingStyle.lazy&&this.appearanceObserver.start(),this.linkInterceptor.start(),this.formInterceptor.start(),this.sourceURLChanged())}disconnect(){this.connected&&(this.connected=!1,this.appearanceObserver.stop(),this.linkInterceptor.stop(),this.formInterceptor.stop())}disabledChanged(){this.loadingStyle==FrameLoadingStyle.eager&&this.loadSourceURL()}sourceURLChanged(){this.loadingStyle!=FrameLoadingStyle.eager&&!this.hasBeenLoaded||this.loadSourceURL()}loadingStyleChanged(){this.loadingStyle==FrameLoadingStyle.lazy?this.appearanceObserver.start():(this.appearanceObserver.stop(),this.loadSourceURL())}async loadSourceURL(){if(!this.settingSourceURL&&this.enabled&&this.isActive&&(this.reloadable||this.sourceURL!=this.currentURL)){var t=this.currentURL;if(this.currentURL=this.sourceURL,this.sourceURL)try{this.element.loaded=this.visit(expandURL(this.sourceURL)),this.appearanceObserver.stop(),await this.element.loaded,this.hasBeenLoaded=!0}catch(e){throw this.currentURL=t,e}}}async loadResponse(e){(e.redirected||e.succeeded&&e.isHTML)&&(this.sourceURL=e.response.url);try{var t,s,r,i=await e.responseHTML;i&&(t=parseHTMLDocument(i)["body"],s=new Snapshot(await this.extractForeignFrameElement(t)),r=new FrameRenderer(this.view.snapshot,s,!1,!1),this.view.renderPromise&&await this.view.renderPromise,await this.view.render(r),session.frameRendered(e,this.element),session.frameLoaded(this.element),this.fetchResponseLoaded(e))}catch(e){console.error(e),this.view.invalidate()}finally{this.fetchResponseLoaded=()=>{}}}elementAppearedInViewport(e){this.loadSourceURL()}shouldInterceptLinkClick(e,t){return!e.hasAttribute("data-turbo-method")&&this.shouldInterceptNavigation(e)}linkClickIntercepted(e,t){this.reloadable=!0,this.navigateFrame(e,t)}shouldInterceptFormSubmission(e,t){return this.shouldInterceptNavigation(e,t)}formSubmissionIntercepted(e,t){this.formSubmission&&this.formSubmission.stop(),this.reloadable=!1,this.formSubmission=new FormSubmission(this,e,t);e=this.formSubmission.fetchRequest;this.prepareHeadersForRequest(e.headers,e),this.formSubmission.start()}prepareHeadersForRequest(e,t){e["Turbo-Frame"]=this.id}requestStarted(e){markAsBusy(this.element)}requestPreventedHandlingResponse(e,t){this.resolveVisitPromise()}async requestSucceededWithResponse(e,t){await this.loadResponse(t),this.resolveVisitPromise()}requestFailedWithResponse(e,t){console.error(t),this.resolveVisitPromise()}requestErrored(e,t){console.error(t),this.resolveVisitPromise()}requestFinished(e){clearBusyState(this.element)}formSubmissionStarted({formElement:e}){markAsBusy(e,this.findFrameElement(e))}formSubmissionSucceededWithResponse(e,t){var s=this.findFrameElement(e.formElement,e.submitter);this.proposeVisitIfNavigatedWithAction(s,e.formElement,e.submitter),s.delegate.loadResponse(t)}formSubmissionFailedWithResponse(e,t){this.element.delegate.loadResponse(t)}formSubmissionErrored(e,t){console.error(t)}formSubmissionFinished({formElement:e}){clearBusyState(e,this.findFrameElement(e))}allowsImmediateRender(e,t){return!0}viewRenderedSnapshot(e,t){}viewInvalidated(){}async visit(e){const t=new FetchRequest(this,FetchMethod.get,e,new URLSearchParams,this.element);return null!=(e=this.currentFetchRequest)&&e.cancel(),this.currentFetchRequest=t,new Promise(e=>{this.resolveVisitPromise=()=>{this.resolveVisitPromise=()=>{},this.currentFetchRequest=null,e()},t.perform()})}navigateFrame(e,t,s){var r=this.findFrameElement(e,s);this.proposeVisitIfNavigatedWithAction(r,e,s),r.setAttribute("reloadable",""),r.src=t}proposeVisitIfNavigatedWithAction(s,e,t){const r=getAttribute("data-turbo-action",t,e,s);if(isAction(r)){const i=new SnapshotSubstitution(s)["visitCachedSnapshot"];s.delegate.fetchResponseLoaded=e=>{var t;s.src&&({statusCode:e,redirected:t}=e,e={statusCode:e,redirected:t,responseHTML:s.ownerDocument.documentElement.outerHTML},session.visit(s.src,{action:r,response:e,visitCachedSnapshot:i,willRender:!1}))}}}findFrameElement(e,t){return null!=(t=getFrameElementById(getAttribute("data-turbo-frame",t,e)||this.element.getAttribute("target")))?t:this.element}async extractForeignFrameElement(e){var t,s=CSS.escape(this.id);try{if(t=activateElement(e.querySelector("turbo-frame#"+s),this.currentURL))return t;if(t=activateElement(e.querySelector(`turbo-frame[src][recurse~=${s}]`),this.currentURL))return await t.loaded,await this.extractForeignFrameElement(t);console.error(`Response has no matching element`)}catch(e){console.error(e)}return new FrameElement}formActionIsVisitable(e,t){return locationIsVisitable(expandURL(getAction(e,t)),this.rootLocation)}shouldInterceptNavigation(e,t){var s=getAttribute("data-turbo-frame",t,e)||this.element.getAttribute("target");if(e instanceof HTMLFormElement&&!this.formActionIsVisitable(e,t))return!1;if(!this.enabled||"_top"==s)return!1;if(s){s=getFrameElementById(s);if(s)return!s.disabled}return!(!session.elementDriveEnabled(e)||t&&!session.elementDriveEnabled(t))}get id(){return this.element.id}get enabled(){return!this.element.disabled}get sourceURL(){if(this.element.src)return this.element.src}get reloadable(){return this.findFrameElement(this.element).hasAttribute("reloadable")}set reloadable(e){var t=this.findFrameElement(this.element);e?t.setAttribute("reloadable",""):t.removeAttribute("reloadable")}set sourceURL(e){this.settingSourceURL=!0,this.element.src=null!=e?e:null,this.currentURL=this.element.src,this.settingSourceURL=!1}get loadingStyle(){return this.element.loading}get isLoading(){return void 0!==this.formSubmission||void 0!==this.resolveVisitPromise()}get isActive(){return this.element.isActive&&this.connected}get rootLocation(){var e=this.element.ownerDocument.querySelector('meta[name="turbo-root"]');return expandURL(null!=(e=null==e?void 0:e.content)?e:"/")}}class SnapshotSubstitution{constructor(e){this.visitCachedSnapshot=({element:e})=>{var{id:t,clone:s}=this;null!=(e=e.querySelector("#"+t))&&e.replaceWith(s)},this.clone=e.cloneNode(!0),this.id=e.id}}function getFrameElementById(e){if(null!=e){e=document.getElementById(e);if(e instanceof FrameElement)return e}}function activateElement(e,t){if(e){var s=e.getAttribute("src");if(null!=s&&null!=t&&urlsAreEqual(s,t))throw new Error(`Matching element has a source URL which references itself`);if((e=e.ownerDocument!==document?document.importNode(e,!0):e)instanceof FrameElement)return e.connectedCallback(),e.disconnectedCallback(),e}}const StreamActions={after(){this.targetElements.forEach(e=>{var t;return null==(t=e.parentElement)?void 0:t.insertBefore(this.templateContent,e.nextSibling)})},append(){this.removeDuplicateTargetChildren(),this.targetElements.forEach(e=>e.append(this.templateContent))},before(){this.targetElements.forEach(e=>{var t;return null==(t=e.parentElement)?void 0:t.insertBefore(this.templateContent,e)})},prepend(){this.removeDuplicateTargetChildren(),this.targetElements.forEach(e=>e.prepend(this.templateContent))},remove(){this.targetElements.forEach(e=>e.remove())},replace(){this.targetElements.forEach(e=>e.replaceWith(this.templateContent))},update(){this.targetElements.forEach(e=>{e.innerHTML="",e.append(this.templateContent)})}};class StreamElement extends HTMLElement{async connectedCallback(){try{await this.render()}catch(e){console.error(e)}finally{this.disconnect()}}async render(){var e;return null!=(e=this.renderPromise)?e:this.renderPromise=(async()=>{this.dispatchEvent(this.beforeRenderEvent)&&(await nextAnimationFrame(),this.performAction())})()}disconnect(){try{this.remove()}catch(e){}}removeDuplicateTargetChildren(){this.duplicateChildren.forEach(e=>e.remove())}get duplicateChildren(){var e,t=this.targetElements.flatMap(e=>[...e.children]).filter(e=>!!e.id);const s=[...null==(e=this.templateContent)?void 0:e.children].filter(e=>!!e.id).map(e=>e.id);return t.filter(e=>s.includes(e.id))}get performAction(){if(this.action){var e=StreamActions[this.action];if(e)return e;this.raise("unknown action")}this.raise("action attribute is missing")}get targetElements(){return this.target?this.targetElementsById:this.targets?this.targetElementsByQuery:void this.raise("target or targets attribute is missing")}get templateContent(){return this.templateElement.content.cloneNode(!0)}get templateElement(){if(this.firstElementChild instanceof HTMLTemplateElement)return this.firstElementChild;this.raise("first child element must be a element")}get action(){return this.getAttribute("action")}get target(){return this.getAttribute("target")}get targets(){return this.getAttribute("targets")}raise(e){throw new Error(this.description+": "+e)}get description(){var e;return null!=(e=(null!=(e=this.outerHTML.match(/<[^>]+>/))?e:[])[0])?e:""}get beforeRenderEvent(){return new CustomEvent("turbo:before-stream-render",{bubbles:!0,cancelable:!0})}get targetElementsById(){var e=null==(e=this.ownerDocument)?void 0:e.getElementById(this.target);return null!==e?[e]:[]}get targetElementsByQuery(){var e=null==(e=this.ownerDocument)?void 0:e.querySelectorAll(this.targets);return 0!==e.length?Array.prototype.slice.call(e):[]}}FrameElement.delegateConstructor=FrameController,customElements.define("turbo-frame",FrameElement),customElements.define("turbo-stream",StreamElement),(()=>{let e=document.currentScript;if(e&&!e.hasAttribute("data-turbo-suppress-warning"))for(;e=e.parentElement;)if(e==document.body)return console.warn(unindent`
+ You are loading Turbo from a
+
+
+ Requirements Tool Specification (L1) - PDF
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Table of contents
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 15.3
+
+
+ Free
+
+
+
+
+
+
+
+
+ STATEMENT:
+
+
+
+ The StrictDoc project is structured around two distinct requirement documents that guide its
+ development:
+
+ - The "Requirements Tool Specification" (this document), which is a higher-level document.
+ - The "StrictDoc Requirements Specification," a more detailed and lower-level document, separate from
+ this one.
+
+ This document, the Requirements Tool Specification, delineates the general requirements for an
+ open-source Requirements Tool, with a focus that remains agnostic of the specific implementation details
+ of StrictDoc. Its primary goal is to provide a comprehensive, implementation-neutral overview of what
+ capabilities a Requirements Tool should possess, emphasizing the 'WHAT' aspect.
+ In contrast, the StrictDoc Requirements Specification, the second document, delves deeply into the
+ 'HOW' aspect of StrictDoc’s implementation. It builds upon the high-level requirements set out in this
+ document, treating them as parent requirements to guide its detailed development approach.
+
+
+
+
+
+
+
+
+
+
+ 1. Summary of user needs
+
+
+
+ MID:
+
+ 668d18a7489043b38dd435933319e8e7
+
+
+
+
+
+
+
+ STATEMENT:
+
+
+
+ This section offers an overview of the necessary capabilities of a requirements and documentation
+ management tool.
+
+
+
+
+
+
+
+
+
+
+ 1.1. Free and open source tool
+
+
+
+ MID:
+
+ 1cbe275272994922a942fd088fa969d8
+
+
+
+
+
+
+
+ STATEMENT:
+
+
+
+ The primary user need and entry point for this Requirements Tool specification is the availability of
+ free, lightweight, yet capable software for creating requirements specifications and other technical
+ documentation. The tool should facilitate the creation of requirements specifications and technical
+ documents, effectively lowering the entry barrier for requirements engineering and technical
+ documentation writing.
+ It is assumed throughout this document that the requirements tool will be developed as open-source
+ software available at no cost. However, with minor adjustments, these requirements could also apply to
+ commercial requirements tools. See 🔗 15.
+ Licensing and distribution.
+
+
+
+
+
+
+
+
+
+
+ 1.2. Document types
+
+
+
+ MID:
+
+ 18136bcb9a5b4226a7a95d27dae49805
+
+
+
+
+
+
+
+ STATEMENT:
+
+
+
+ A requirements tool is very often also a documentation writing and management tool, so, besides the
+ requirements editing functionality, the tool shall be able to accommodate for the variety of documents
+ and templates used in different industries.
+ The variety comes from:
+
+ - Supporting arbitrary documentation structures, e.g., non-nested vs. deeply nested documents.
+ - Supporting a rich set of visualization mechanisms. Supporting images, diagrams, tables, text markup,
+ etc.
+ - Supporting custom fields/attributes used by different industries (the criticality levels in various
+ industries, RAIT verification activities in aerospace, status/workflow fields, etc.).
+
+ Examples of typical document types include:
+
+ - Requirements specification
+ - Design document / architecture description document
+ - Interface control document / API reference
+ - User manual
+ - Development plan
+ - Systems engineering plan, management plan
+ - Standard (e.g., ECSS or ISO 26262).
+
+ The documentation/requirements management requirements for a Requirements Tool are specified in the
+ sections 🔗 2. Documentation management and 🔗 3. Requirements management.
+
+
+
+
+
+
+
+
+
+
+
+ 1.2.1. Document structure differences
+
+
+
+ MID:
+
+ 973b586b8a89411ab4f083fd4c262cf5
+ UID:
+
+ SECTION-RTC-Appendix-A-Document-archetypes
+
+
+
+
+
+
+
+ STATEMENT:
+
+
+
+ The table below summarizes various differences observed across industry documents.
+
+ Table: Requirements and specification document
+
+
+
+
+
+
+ | Criteria |
+ Comments |
+
+
+
+
+ | Structure |
+ Non-nested, nested, deeply nested. A structure of a deeply nested specification document can
+ reach 8-10 levels (e.g., Section 1.2.3.4.5.6.7.8 "ABC"). |
+
+
+ | Requirements visual presentation |
+ Requirements are often presented as table cells. The cells can be standalone or a whole section
+ or a document can be a structured as a long table with cells. Alternatively, requirements are
+ rather presented as a section header + text. |
+
+
+ | Unique requirement identifiers (UID) |
+ Some documents provide UIDs for all requirements, some do not. Where the UIDs are missing, the
+ section header numbers are used instead for unique identification. Often, a combination "Number +
+ Title" becomes a reference-able identifier. |
+
+
+ | Requirement titles |
+ Not all documents provide requirement titles. When the requirement titles are missing, the
+ grouping is may be provided by sections/chapters. When the titles are present, the requirement
+ titles can also be section titles. |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1.3. Workflows
+
+
+
+ MID:
+
+ 52b6175f03d7495a9fa8dbffa36aeff4
+ UID:
+
+ SECTION-LRTS-Workflows
+
+
+
+
+
+
+
+ STATEMENT:
+
+
+
+ Besides supporting a variety of document types, a Requirements Tool shall also support and integrate
+ well with multiple documentation and requirements management workflows.
+ At least the following workflows have been identified to be relevant:
+
+
+
+
+
+
+
+ | Workflow |
+ Description |
+
+
+
+
+ | Requirements analysis and prototyping |
+ Early phases of the project. Requirements are drafted out quickly. The higher-level picture and
+ coverage of all topics may be more important than specific details. |
+
+
+ | Requirements compliance, traceability and justification |
+ Demonstrating the correctness of specification, also for contractual purposes. Every aspect
+ shall be traceable. |
+
+
+ | Requirements implementation |
+ Assisting software engineers in implementing requirements in source code. Making links between
+ requirements and source code implementation units, e.g., files, functions, code fragments. Linking
+ source code implementation units to requirements using special markers left in source code. |
+
+
+ | Requirements validation/verification workflow (RAIT) |
+ Verifying the correctness of requirements themselves and the validity of the information they
+ communicate. |
+
+
+ | Configuration management, change management |
+ Time machine and Diff functions. Maintaining requirements baselines (v1, v1.1, v2, etc.). |
+
+
+ | Reporting |
+ Progress reports, statistics, metrication. |
+
+
+ | Collaboration on requirements |
+ Supporting multiple users to collaborate on a documentation tree. |
+
+
+ | Requirements exchange |
+ Integration between distinct projects requirements trees. Example: An embedded software project
+ has its own requirements. The developers want to integrate a requirements subtree of another
+ product that is integrated to the parent project as an off-the-shelf solution. |
+
+
+ | Formal reviews |
+ Formal review of documentation. Walkthroughs, inspections. Version control of delivered
+ documentation packages. Assessment of progress reports achieved. |
+
+
+ | Interoperability with industry standards. |
+ Supporting seamless integration between a project documentation tree and applicable standards.
+ |
+
+
+
+ The section 🔗 4. Existing workflows contains the
+ workflow-related requirements for a Requirements Tool.
+
+
+
+
+
+
+
+
+
+
+ 1.4. Target audience
+
+
+
+ MID:
+
+ 08d547a3b04d485ca1f5a3a94a664ee1
+
+
+
+
+
+
+
+ STATEMENT:
+
+
+
+ A Requirements Tool may have different users, each with a different role, experience and background
+ which necessitates the requirements towards usability, installation, and user experience.
+ The following user groups are preliminarily identified as especially relevant:
+ Engineering professionals
+ This group includes:
+
+ - Systems engineers
+ - Requirements engineers
+ - Assurance experts in quality, safety/security, verification/validation
+
+ For these professionals, the Requirements Tool should offer robust functionality that is adequate for
+ complex system design and detailed requirements tracking, ensuring that all aspects of system integrity
+ and compliance are met efficiently.
+ Management
+ The focus of this group is more on the progress and compliance aspects. They require high-level
+ overviews and reporting capabilities in the tool, to track project milestones, manage risks, and ensure
+ that the development is adhering to the predefined requirements and industry standards.
+ Software engineers
+ For software engineers, the Requirements Tool shall be closely integrated with their software
+ engineering workflow, e.g., it has interfaces with software version control systems, software IDEs, and
+ source code repositories. This integration ensures a seamless transition between requirement
+ specification and software development tasks.
+ IT/DevOps
+ This group of users may not work with a Requirements Tool directly but is still an important
+ stakeholder. The Tool shall be easy to install and deploy. It shall be easy to maintain and upgrade the
+ tool, with support for automated updates and compatibility with various IT infrastructures.
+ General audience
+ Not all users of a requirements tool must have an engineering background. In fact, there are many
+ projects where non-technical people have to maintain requirements. The Requirements Tool shall be usable
+ without any technical training required, featuring an intuitive user interface and simplified processes
+ for entering and managing requirements.
+ The requirement sets in the sections 🔗 10.
+ Usability, installation and usage
+ and 🔗 11. Implementation suggestions aim to
+ equip the Requirements Tool with sufficient capabilities to support all of the user groups described
+ above.
+
+
+
+
+
+
+
+
+
+
+
+ 2. Documentation management
+
+
+
+ MID:
+
+ f1ffdc7f78134d4b98f3c90e9be40cc7
+ UID:
+
+ SECTION-RTS-Documentation-management
+
+
+
+
+
+
+
+ STATEMENT:
+
+
+
+ This section outlines the requirements towards a Requirements Tool as a documentation tool.
+ The requirements of this group are dedicated to the core tasks of documentation management:
+
+ - Writing, structuring and managing documents
+ - Complementing documents with meta information
+ - Versioning documents.
+
+
+
+
+
+
+
+
+
+
+
+ 2.1. Documents (CRUD)
+
+ MID:
+
+ 72d0dd23dedd4907b4a8924debe7343b
+ UID:
+
+ SDOC-SSS-3
+ STATUS:
+
+ Active
+ STATEMENT:
+
+
+
+ The Requirements Tool shall provide the CRUD operations for document management:
+
+ - Create document
+ - Read document
+ - Update document
+ - Delete document.
+
+
+
+ RATIONALE:
+
+
+
+ The CRUD operations are essential operations of document management. They are at the core of a
+ documentation management tool.
+
+
+ RELATIONS (Child):
+
+
+
+
+
+
+
+
+
+
+
+ 2.2. Browsing documentation tree
+
+ MID:
+
+ 9841bc9a56d740dd9e7988e52339618c
+ UID:
+
+ SDOC-SSS-91
+ STATUS:
+
+ Active
+ STATEMENT:
+
+
+
+ The Requirements Tool shall provide browsing of the documentation tree.
+
+
+ RELATIONS (Child):
+
+
+
+
+
+
+
+
+
+
+
+ 2.3. Documents with nested sections/chapters structure
+
+ MID:
+
+ c4de5f1f46f343b6b4e8dc2a6121b0a2
+ UID:
+
+ SDOC-SSS-51
+ STATUS:
+
+ Active
+ STATEMENT:
+
+
+
+ The Requirements Tool shall allow management of documents with nested sections/chapters structure.
+
+
+ RELATIONS (Child):
+
+
+
+
+
+
+
+
+
+
+
+ 2.4. Assembling documents from fragments
+
+ MID:
+
+ 5236f36f278140539e347bacea921118
+ UID:
+
+ SDOC-SSS-52
+ STATUS:
+
+ Active
+ STATEMENT:
+
+
+
+ The Requirements Tool shall allow composing documents from other documents or fragments.
+ NOTE: If a Requirements Tool implements stores documents in a file system, the composition can be
+ arranged at a file level when a parent document file includes the child fragment files and produces a
+ composite document.
+
+
+ RATIONALE:
+
+
+
+ Composable documents allow assembling documents from multiple smaller documents which can be standalone
+ documents or document fragments. This feature is particularly useful for managing extensive documents
+ that can be more effectively organized and handled when divided into smaller document sections.
+
+
+ RELATIONS (Parent):
+
+
+
+ RELATIONS (Child):
+
+
+
+
+
+
+
+
+
+
+
+ 2.5. Document meta information (UID, version, authors, signatures, etc)
+
+ MID:
+
+ 8aeecdfa139341588d6ab8c0c3606a9b
+ UID:
+
+ SDOC-SSS-53
+ STATUS:
+
+ Active
+ STATEMENT:
+
+
+
+ The Requirements Tool shall support management of document meta information.
+
+
+ RELATIONS (Child):
+
+
+
+
+
+
+
+
+
+
+
+ 2.6. Document versioning
+
+ MID:
+
+ d1883b65e17442c0a22987d4ad415cb6
+ UID:
+
+ SDOC-SSS-75
+ STATUS:
+
+ Active
+ STATEMENT:
+
+
+
+ The Requirements Tool shall provide capabilities for document versioning.
+
+
+ RELATIONS (Child):
+
+
+
+
+
+
+
+
+
+
+
+ 2.7. Text formatting capabilities
+
+ MID:
+
+ b8d7b22fd8a6478a9a21ecaa60cf0028
+ UID:
+
+ SDOC-SSS-63
+ STATUS:
+
+ Active
+ STATEMENT:
+
+
+
+ The Requirements Tool shall provide "rich text" formatting capabilities which includes but not limited
+ to:
+
+ - Headings
+ - Lists
+ - Tables
+ - UML diagrams
+ - etc.
+
+
+
+ RELATIONS (Parent):
+
+
+
+ RELATIONS (Child):
+
+
+
+
+
+
+
+
+
+
+
+ 2.8. Content search
+
+ MID:
+
+ 3bb5252d75bc486b98e7606fb642bac0
+ UID:
+
+ SDOC-SSS-95
+ STATUS:
+
+ Active
+ STATEMENT:
+
+
+
+ The Requirements Tool shall provide functionality to search content in the documentation tree.
+
+
+ RATIONALE:
+
+
+
+ Efficient navigation of large documentation trees requires search capabilities so that users can
+ quickly locate relevant information without manually browsing through all content.
+
+
+ RELATIONS (Child):
+
+
+
+
+
+
+
+
+
+
+
+
+ 3. Requirements management
+
+
+
+ MID:
+
+ fd227b9cfdc54d7db3134cdb925bde87
+ UID:
+
+ SECTION-RTS-Requirements-management
+
+
+
+
+
+
+
+ STATEMENT:
+
+
+
+ This section outlines the requirements towards a Requirements Tool as a requirements management tool.
+
+ The following core aspects of the requirements management are covered:
+
+ - Writing and structuring requirements
+ - Linking requirements with other requirements
+ - Managing requirement unique identifiers (UID)
+ - Requirement verification.
+
+
+
+
+
+
+
+
+
+
+
+ 3.1. Requirements CRUD
+
+ MID:
+
+ 6e6f1464c47f4ced8e14c4153f40618b
+ UID:
+
+ SDOC-SSS-4
+ STATUS:
+
+ Active
+ STATEMENT:
+
+
+
+ The Requirements Tool shall enable the main requirements management operations:
+
+ - Create a requirement
+ - Read / view / browse a requirement
+ - Update / edit a requirement
+ - Delete a requirement.
+
+
+
+ RATIONALE:
+
+
+
+ The CRUD operations are at the core of the requirements management.
+
+
+ RELATIONS (Child):
+
+
+
+
+
+
+
+
+
+
+
+ 3.2. Minimal requirement field set
+
+ MID:
+
+ db42ad4b504e48e0bf51b4d82529a888
+ UID:
+
+ SDOC-SSS-61
+ STATUS:
+
+ Active
+ STATEMENT:
+
+
+
+ The Requirements Tool shall support at least the following requirement field set:
+
+ - UID
+ - STATUS
+ - TITLE
+ - STATEMENT
+ - RATIONALE
+ - COMMENT
+ - RELATIONS (connections with other requirements).
+
+
+
+ RATIONALE:
+
+
+
+ The selection of the minimal set is based on what is common in the industries (e.g., automotive, space,
+ etc).
+
+
+ COMMENT:
+
+
+
+ The other fields common to each industry can be customized with custom fields handled by other
+ requirements.
+
+
+ RELATIONS (Parent):
+
+
+
+ RELATIONS (Child):
+
+
+
+
+
+
+
+
+
+
+
+ 3.3. Custom fields
+
+ MID:
+
+ a69bae43b3224dfc8439a88451a98395
+ UID:
+
+ SDOC-SSS-62
+ STATUS:
+
+ Active
+ STATEMENT:
+
+
+
+ The requirements tool shall support configuring a requirement item with an arbitrary set of fields.
+ NOTE: Examples of typical fields include: UID, Title, Statement, Rationale, Comment. Other fields that
+ are used very often are: Status, Tags, Criticality level, Priority, etc.
+
+
+ RATIONALE:
+
+
+
+ The tool shall not constrain a user in which fields they are able to use for their projects.
+
+
+ RELATIONS (Parent):
+
+
+
+ RELATIONS (Child):
+
+
+
+
+
+
+
+
+
+
+
+ 3.4. Structuring requirements in documents
+
+ MID:
+
+ 5f89bdaa6cb74e2a8b9b030b6237b7ef
+ UID:
+
+ SDOC-SSS-64
+ STATUS:
+
+ Active
+ STATEMENT:
+
+
+
+ The Requirements Tool shall support structuring requirements in documents.
+
+
+ RATIONALE:
+
+
+
+ The industry works with requirements documents. The documents have sections/chapters and requirements.
+
+
+
+ RELATIONS (Parent):
+
+
+
+ RELATIONS (Child):
+
+
+
+
+
+
+
+
+
+
+
+ 3.5. Move requirement nodes within document
+
+ MID:
+
+ 65575cc8a87e4d4480ccdf89d1fb6d67
+ UID:
+
+ SDOC-SSS-5
+ STATUS:
+
+ Active
+ STATEMENT:
+
+
+
+ The Requirements Tool shall allow moving nodes (sections, requirements) within the containing document.
+
+
+
+ RELATIONS (Child):
+
+
+
+
+
+
+
+
+
+
+
+ 3.6. Move nodes between documents
+
+ MID:
+
+ 06ab121d3c0f4d8c94652323b8f735c6
+ UID:
+
+ SDOC-SSS-70
+ STATUS:
+
+ Active
+ STATEMENT:
+
+
+
+ The Requirements Tool shall allow moving nodes (sections, requirements) between documents.
+
+
+ RELATIONS (Child):
+
+
+
+
+
+
+
+
+
+
+
+ 3.7. Auto-provision of Requirement UIDs
+
+ MID:
+
+ 637c129a91804d8cbe2280c1af14836d
+ UID:
+
+ SDOC-SSS-6
+ STATUS:
+
+ Active
+ STATEMENT:
+
+
+
+ The Requirements Tool shall provide controls for automatic generation of requirements UIDs.
+
+
+ RATIONALE:
+
+
+
+ When a document is large, it becomes harder to manage the assignment of the new requirements
+ identifiers by manually exploring which requirement UID has not been assigned yet. The provision of
+ automatically generated UIDs is a convenience feature that improves the user experience significantly.
+
+
+
+ RELATIONS (Parent):
+
+
+
+ RELATIONS (Child):
+
+
+
+
+
+
+
+
+
+
+
+ 3.8. Link requirements together
+
+ MID:
+
+ 1ce495a5194044d4a7a3dd030f766c9f
+ UID:
+
+ SDOC-SSS-7
+ STATUS:
+
+ Active
+ STATEMENT:
+
+
+
+ The Requirements Tool shall allow bi-directional linking of requirements nodes together using Parent or
+ Child relations.
+
+
+ RATIONALE:
+
+
+
+ The requirement ensures a classic capability of a requirement tool: linking requirements together
+ enables bi-directional traceability which helps in understanding how the requirements are related to
+ each other.
+
+
+ RELATIONS (Parent):
+
+
+
+ RELATIONS (Child):
+
+
+
+
+
+
+
+
+
+
+
+ 3.9. Multiple link roles
+
+ MID:
+
+ 44b9d75e50c84d6c8424cfb8a42a0771
+ UID:
+
+ SDOC-SSS-8
+ STATUS:
+
+ Active
+ STATEMENT:
+
+
+
+ The Requirements Tool shall support the link roles.
+ Example of roles for a child-to-parent link: "verifies", "implements", "satisfies", etc.
+
+
+ RATIONALE:
+
+
+
+ Different industries maintain custom conventions for naming the relations between requirements and
+ other nodes such as tests or other artefacts.
+
+
+ RELATIONS (Parent):
+
+
+
+ RELATIONS (Child):
+
+
+
+
+
+
+
+
+
+
+
+ 3.10. Reverse parent links
+
+ MID:
+
+ 387bd5ff0e4a4a97962661e9d7451f19
+ UID:
+
+ SDOC-SSS-71
+ STATUS:
+
+ Active
+ STATEMENT:
+
+
+
+ The Requirements Tool shall support the Reverse Parent relationship.
+
+
+ RELATIONS (Child):
+
+
+
+
+
+
+
+
+
+
+
+ 3.11. Unique identification of requirements
+
+ MID:
+
+ 3348caaed8d44be0928cc6f3c7414094
+ UID:
+
+ SDOC-SSS-89
+ STATUS:
+
+ Active
+ STATEMENT:
+
+
+
+ The Requirements Tool shall provide means for unique identification of every requirement.
+
+
+ RATIONALE:
+
+
+
+ The requirement ensures a classic capability of a requirement tool:
+
+ - The unique identifiers help the users in identifying the requirements, both when reading a
+ requirements document and when discussing requirements.
+ - The unique identifiers are used for linking requirements together. The requirements tool stores the
+ identifiers in a global database and can resolve the links, following the unique identifiers they
+ point to.
+
+
+
+ RELATIONS (Child):
+
+
+
+
+
+
+
+
+
+
+
+ 3.12. Requirements database consistency checks
+
+ MID:
+
+ 3850f0b8c8294455bf7be9e2acddbd40
+ UID:
+
+ SDOC-SSS-47
+ STATUS:
+
+ Active
+ STATEMENT:
+
+
+
+ The Requirements Tool shall provide a validation mechanism that ensures the integrity of requirements
+ and connections between them.
+ NOTE: Examples of integrity checks:
+
+ - Requirements have correct fields.
+ - Requirements do not form cycles.
+ - Requirements only link to other requirements as specified in a project configuration.
+
+
+
+ RELATIONS (Child):
+
+
+
+
+
+
+
+
+
+
+
+ 3.13. Requirement syntax validation (e.g. EARS)
+
+ MID:
+
+ 1216cb617c0f495a9c96471ef72bf80f
+ UID:
+
+ SDOC-SSS-57
+ STATUS:
+
+ Active
+ STATEMENT:
+
+
+
+ The Requirements Tool shall provide capabilities for validating requirements according to the EARS
+ syntax.
+
+
+ RELATIONS (Child):
+
+
+
+
+
+
+
+
+
+
+
+
+ 4. Existing workflows
+
+
+
+ MID:
+
+ ec52fa5cc1714b07863eb7da9432be1d
+ UID:
+
+ SECTION-SSSS-Existing-workflows
+
+
+
+
+
+
+
+ STATEMENT:
+
+
+
+ This section captures the requirements towards specific workflows that a Requirements Tool should
+ support as outlined in 🔗 1.3. Workflows.
+
+
+
+
+
+
+
+
+
+
+ 4.1. Excel-like viewing and editing of requirements
+
+ MID:
+
+ 831debedfa0e4e4c8434021569f96bad
+ UID:
+
+ SDOC-SSS-73
+ STATUS:
+
+ Active
+ STATEMENT:
+
+
+
+ The Requirements Tool shall provide an Excel-like user interface for viewing and editing requirements.
+
+ NOTE: This interface does not have to be the only or a default interface.
+
+
+ RATIONALE:
+
+
+
+ As recognized by the parent requirement, some requirements-based workflows are naturally easier when
+ the requirements content is presented in a form of a table, as opposed to a document with a nested
+ chapter structure.
+
+
+ RELATIONS (Child):
+
+
+
+
+
+
+
+
+
+
+
+ 4.2. 1000-feet view
+
+ MID:
+
+ 5d412989005e4bc3b5dcfd94675615dc
+ UID:
+
+ SDOC-SSS-56
+ STATUS:
+
+ Active
+ STATEMENT:
+
+
+
+ The Requirements Tool shall provide a "1000-feet view" kind of requirements visualization.
+
+
+ RATIONALE:
+
+
+
+ Compared to the other visualizations, such a visualization helps to "see the forest for the trees".
+ Seeing requirements and their sections all at once helps to visualize groups of requirements and better
+ understand the relationships between them.
+
+
+ RELATIONS (Child):
+
+
+
+
+
+
+
+
+
+
+
+ 4.3. Traceability matrices
+
+ MID:
+
+ 5eb553abd3944bffbd003e37b3d1c5a5
+ UID:
+
+ SDOC-SSS-28
+ STATUS:
+
+ Active
+ STATEMENT:
+
+
+
+ The Requirements Tool shall support generation of traceability matrices.
+
+
+ RELATIONS (Child):
+
+
+
+
+
+
+
+
+
+
+
+ 4.4. Compliance matrices
+
+ MID:
+
+ 06f0bb40f76142f4ba59d037aaedc9de
+ UID:
+
+ SDOC-SSS-48
+ STATUS:
+
+ Active
+ STATEMENT:
+
+
+
+ The Requirements Tool shall allow generating a Compliance Matrix document.
+
+
+ RELATIONS (Child):
+
+
+
+
+
+
+
+
+
+
+
+ 4.5. Requirements coverage
+
+ MID:
+
+ 74ffae6279bc4e4095c03d6a247c3599
+ UID:
+
+ SDOC-SSS-29
+ STATUS:
+
+ Active
+ STATEMENT:
+
+
+
+ The Requirements Tool shall provide means for getting information about the requirements coverage of a
+ given project.
+ NOTE: The requirements coverage can be presented in a tabular form or visualized with a set of graphs.
+
+
+
+ RATIONALE:
+
+
+
+ The requirements coverage information helps to assess whether all requirements are linked to each
+ other, whether all requirements are connected to implementation, test or other artifacts. Additionally,
+ the requirements coverage information can provide metrics for measuring a project's progress, e.g., "50%
+ of requirements have been traced to the source code". The requirement ensures that the requirements tool
+ provides this feature.
+
+
+ RELATIONS (Child):
+
+
+
+
+
+
+
+
+
+
+
+ 4.6. Progress report
+
+ MID:
+
+ e0e6d1f883764719919238e4974dccef
+ UID:
+
+ SDOC-SSS-49
+ STATUS:
+
+ Active
+ STATEMENT:
+
+
+
+ The Requirements Tool shall allow generating a Progress Report document.
+ NOTE: A progress report document shall include at least the following Key Performance Indicators.
+ Project-level KPIs:
+
+ - Total number of requirements
+ - Total number of requirements without parent (excluding top-level and derived)
+ - Total number of TBD/TBC
+ - Total number of requirements without rationale
+ - Tags breakdown
+
+ Document-level KPIs: the same but per document.
+
+
+ RELATIONS (Child):
+
+
+
+
+
+
+
+
+
+
+
+ 4.7. Change management
+
+ MID:
+
+ ed4bd232bed84eda977263fa03e75b80
+ UID:
+
+ SDOC-SSS-74
+ STATUS:
+
+ Active
+ STATEMENT:
+
+
+
+ The Requirements Tool shall provide capabilities for change management:
+
+ - Visualizing changes between project tree versions.
+ - Visualizing changes between document versions.
+ - Visualizing the impact that a changed requirement has on a project tree.
+
+
+
+ RELATIONS (Child):
+
+
+
+
+
+
+
+
+
+
+
+
+ 5. Requirements and source code
+
+
+
+ MID:
+
+ 8b1da9907bc847c989dc807b7dff2a05
+ UID:
+
+ SECTION-RTS-Requirements-and-source-code
+
+
+
+
+
+
+
+
+
+ 5.1. Traceability between requirements and source code
+
+ MID:
+
+ 4692362c77974fb8bcbeefdc248d0e89
+ UID:
+
+ SDOC-SSS-72
+ STATUS:
+
+ Active
+ STATEMENT:
+
+
+
+ The Requirements Tool shall support bi-directional tracing between requirements content and
+ implementation source code with only minimal changes needed in the source code.
+ NOTE: The Requirements Tool does not necessarily have to implement the complete tracing process. It may
+ delegate parts of the traceability task to other tools, e.g., Doxygen, Lobster, etc.
+
+
+ RATIONALE:
+
+
+
+ This requirement connects the worlds of requirements and source code which ensures that the
+ traceability between requirements-implementation and requirements-tests can be achieved in an explicit
+ way. Without a direct support of tracing requirements to source code by a requirements tool, the users
+ have to find workarounds that are less efficient.
+
+
+ RELATIONS (Parent):
+
+
+
+ RELATIONS (Child):
+
+
+
+
+
+
+
+
+
+
+
+
+ 6. Requirements exchange formats (export/import)
+
+
+
+ MID:
+
+ cd9e353e07ae4d50b1aa08999854aa02
+ UID:
+
+ SECTION-RTS-Requirements-exchange-formats-export-import
+
+
+
+
+
+
+
+ STATEMENT:
+
+
+
+ This section captures the requirements related to "Requirements exchange" as outlined in the section 🔗 1.3. Workflows.
+ The Requirements Tool should fundamentally support the exchange of documentation and requirements with
+ other tools. Importing data into this tool and exporting data from it to other tools should be
+ straightforward. The key focus of this section's requirements is on enabling seamless access to
+ requirements and documentation data.
+
+
+
+
+
+
+
+
+
+
+ 6.1. PDF export
+
+ MID:
+
+ 086eb992322d4c43ad91a40f6c9f9952
+ UID:
+
+ SDOC-SSS-96
+ STATUS:
+
+ Active
+ STATEMENT:
+
+
+
+ The Requirements Tool shall support exporting documentation content to PDF, both individual documents
+ and complete documentation trees.
+
+
+ RATIONALE:
+
+
+
+ PDF is one of the most common formats for reviewing documentation.
+
+
+ RELATIONS (Child):
+
+
+
+
+
+
+
+
+
+
+
+ 6.2. ReqIF export/import
+
+ MID:
+
+ 73e70548c2cf415f94adbf1066d5fe4b
+ UID:
+
+ SDOC-SSS-58
+ STATUS:
+
+ Active
+ STATEMENT:
+
+
+
+ The Requirements Tool shall support exporting/importing requirements content from/to ReqIF format.
+
+
+ RATIONALE:
+
+
+
+ ReqIF is a standard for exchanging requirements. There is currently no other standard of a higher
+ maturity.
+
+
+ RELATIONS (Parent):
+
+
+
+ RELATIONS (Child):
+
+
+
+
+
+
+
+
+
+
+
+ 6.3. CSV export/import
+
+ MID:
+
+ c94de32c2c2e454d81c77724a4f29283
+ UID:
+
+ SDOC-SSS-59
+ STATUS:
+
+ Active
+ STATEMENT:
+
+
+
+ The Requirements Tool shall support exporting/importing requirements content from/to CSV.
+
+
+ RELATIONS (Parent):
+
+
+
+
+
+
+
+
+
+
+
+ 6.4. Excel export/import
+
+ MID:
+
+ f7a600a238e34075ac6b65852492cc2f
+ UID:
+
+ SDOC-SSS-60
+ STATUS:
+
+ Active
+ STATEMENT:
+
+
+
+ The Requirements Tool shall support exporting/importing requirements content from/to Excel.
+
+
+ RELATIONS (Child):
+
+
+
+
+
+
+
+
+
+
+
+ 7. Tool configurability
+
+
+
+ MID:
+
+ 7c112f3a5885477084396fd26387a864
+
+
+
+
+
+
+
+
+
+ 7.1. Project-level configuration
+
+ MID:
+
+ 4550038552894ef69b85b281cff60c60
+ UID:
+
+ SDOC-SSS-92
+ STATUS:
+
+ Active
+ STATEMENT:
+
+
+
+ The Requirements Tool shall provide a solution for configuring the project-level options.
+ NOTE: Examples of project-level options:
+
+ - Project title.
+ - Global settings for the Requirements Tool itself.
+
+
+
+ RATIONALE:
+
+
+
+ The requirement ensures the configurability of the tool for a specific project.
+
+
+ RELATIONS (Child):
+
+
+
+
+
+
+
+
+
+
+
+ 7.2. Document-level configuration
+
+ MID:
+
+ 4550b38552894ef69b85b281cff60360
+ UID:
+
+ SDOC-SSS-93
+ STATUS:
+
+ Active
+ STATEMENT:
+
+
+
+ The Requirements Tool shall provide a solution for configuring the document-level options.
+ NOTE: Examples of document-level options:
+
+ - Document title
+ - Requirement prefix.
+ - Other options local to the content and the presentation of a given document.
+
+
+
+ RATIONALE:
+
+
+
+ Sometimes, the project-level configuration can be not fine-grained enough. The requirement ensures that
+ the requirements tool allows a configuration on a document level.
+
+
+ RELATIONS (Child):
+
+
+
+
+
+
+
+
+
+
+
+
+ 8. Performance
+
+
+
+ MID:
+
+ 56dabce670be4691b35434bda6d6bb36
+ UID:
+
+ SECTION-SSSS-Performance
+
+
+
+
+
+
+
+ STATEMENT:
+
+
+
+ This section captures the performance requirements towards a Requirements Tool.
+
+
+
+
+
+
+
+
+
+
+ 8.1. Support large requirements sets
+
+ MID:
+
+ a0a95079e3c0438bb3ea9e5af7ddddc9
+ UID:
+
+ SDOC-SSS-13
+ STATUS:
+
+ Active
+ STATEMENT:
+
+
+
+ The Requirements Tool shall support requirement trees with at least 10000 requirements.
+
+
+ RELATIONS (Child):
+
+
+
+
+
+
+
+
+
+
+
+ 8.2. Support large project trees
+
+ MID:
+
+ 64b982c9299a4c8eb7031495e940a3f8
+ UID:
+
+ SDOC-SSS-14
+ STATUS:
+
+ Active
+ STATEMENT:
+
+
+
+ The Requirements Tool shall be able to handle documentation packages of at least 100 documents without
+ significant performance degradation.
+
+
+ RELATIONS (Child):
+
+
+
+
+
+
+
+
+
+
+
+ 9. Data integrity
+
+
+
+ MID:
+
+ d1a483f3e321414b83bb4a39b1283293
+
+
+
+
+
+
+
+
+
+ 9.1. Data integrity of documentation/requirements
+
+ MID:
+
+ d1323d222a0040b2b6122c59b3c00f06
+ UID:
+
+ SDOC-SSS-94
+ STATUS:
+
+ Active
+ STATEMENT:
+
+
+
+ The Requirements Tool shall ensure the integrity of stored documentation and requirements data
+ throughout its lifecycle.
+
+
+ RATIONALE:
+
+
+
+ The requirement ensures that the tool and the tool's development includes measures for reducing the
+ risk of any data corruption.
+
+
+ COMMENT:
+
+
+
+ This includes safeguarding against data corruption, loss, and ensuring the reliability of links within
+ the documentation.
+
+
+ RELATIONS (Child):
+
+
+
+
+
+
+
+
+
+
+
+
+ 10. Usability, installation and usage
+
+
+
+ MID:
+
+ 85d2f75b2f074f98ace5ceb5288c09b9
+ UID:
+
+ SECTION-RTC-Usability-installation-and-usage
+
+
+
+
+
+
+
+
+
+ 10.1. General usability
+
+ MID:
+
+ 7e33387f373d427d9e1af522f1e5bbc5
+ UID:
+
+ SDOC-SSS-79
+ STATUS:
+
+ Active
+ STATEMENT:
+
+
+
+ The Requirements Tool shall be accessible to a broad spectrum of users.
+ NOTE: Factors to consider:
+
+ - The cost of a tool.
+ - The easy of installation.
+ - The availability of a graphical user interface.
+ - The availability of a programmatic access to the functions of a tool.
+ - The interoperability of the tool with other tools.
+
+
+
+ RATIONALE:
+
+
+
+ A tool that can be used by a large number of people simplifies its adoption and allows more users to
+ work with documentation and requirements.
+
+
+ RELATIONS (Child):
+
+
+
+
+
+
+
+
+
+
+
+ 10.2. Tool identification
+
+ MID:
+
+ 5461fce7174a4bc79048b3528b699beb
+ UID:
+
+ SDOC-SSS-97
+ STATUS:
+
+ Active
+ STATEMENT:
+
+
+
+ The Requirements Tool shall provide identifying information, including title, release version, and
+ project website links.
+
+
+ RELATIONS (Child):
+
+
+
+
+
+
+
+
+
+
+
+ 10.3. Easy user experience
+
+ MID:
+
+ 57b01915e4624634909dbb40f5d56697
+ UID:
+
+ SDOC-SSS-80
+ STATUS:
+
+ Active
+ STATEMENT:
+
+
+
+ The Requirements Tool shall provide a smooth user experience.
+ NOTE: Documentation and requirements management are composite activities that consist of several types
+ of repetitive tasks. A requirements tool user experience should assist in automating these tasks as far
+ as possible and make the overall workflow efficient and precise.
+
+
+ RELATIONS (Child):
+
+
+
+
+
+
+
+
+
+
+
+ 10.4. Support projects with a large number of users
+
+ MID:
+
+ d3e66072363d4e7ea2e2f9691c094bb2
+ UID:
+
+ SDOC-SSS-81
+ STATUS:
+
+ Active
+ STATEMENT:
+
+
+
+ The Requirements Tool shall be capable of supporting a large number of users.
+
+
+ RATIONALE:
+
+
+
+ Many documentation and requirements projects involve large groups of people. The requirements tool
+ should not become a bottleneck when a number of users grows.
+
+
+ RELATIONS (Child):
+
+
+
+
+
+
+
+
+
+
+
+ 10.5. Individual use (home PC)
+
+ MID:
+
+ db495bc2f11f4f96ace60cdb0bef4d66
+ UID:
+
+ SDOC-SSS-82
+ STATUS:
+
+ Active
+ STATEMENT:
+
+
+
+ The Requirements Tool shall be usable on the normal personal computers, e.g., do not require a special
+ cloud deployment.
+
+
+ RELATIONS (Child):
+
+
+
+
+
+
+
+
+
+
+
+ 10.6. Server-based deployments (IT-friendly setup)
+
+ MID:
+
+ 90562d92b9a7468ba42567bc72cb6ebf
+ UID:
+
+ SDOC-SSS-83
+ STATUS:
+
+ Active
+ STATEMENT:
+
+
+
+ The Requirements Tool shall be deployable to the network of computers, e.g., provide a server instance.
+
+
+
+ COMMENT:
+
+
+
+ Scaling from smaller setups (e.g., Raspberry PI in an office network) to
+ larger in-house and cloud-base installations.
+
+
+ RELATIONS (Child):
+
+
+
+
+
+
+
+
+
+
+
+ 10.7. Requirements database
+
+ MID:
+
+ 4312ed066d19487eba18ec677430e60f
+ UID:
+
+ SDOC-SSS-84
+ STATUS:
+
+ Active
+ STATEMENT:
+
+
+
+ The Requirements Tool shall store documentation and requirements data in a database.
+
+
+ RATIONALE:
+
+
+
+ A database allows:
+
+ - Persistent storage of documentation/requirements data
+ - Versioning
+ - Backups
+ - Exchange of information and access of the same database by multiple users.
+
+
+
+ RELATIONS (Child):
+
+
+
+
+
+
+
+
+
+
+
+ 10.8. Programming access via API (Web)
+
+ MID:
+
+ 81858dda65844dcd9640fdd74badecee
+ UID:
+
+ SDOC-SSS-85
+ STATUS:
+
+ Active
+ STATEMENT:
+
+
+
+ The Requirements Tool shall provide a Web API interface.
+
+
+ RATIONALE:
+
+
+
+ Besides a direct access to the tool's source code, accessing an API deployed to a server provides
+ additional capabilities for getting and manipulating requirements/documentation content.
+
+
+ RELATIONS (Child):
+
+
+
+
+
+
+
+
+
+
+
+ 10.9. Programming access via API (SDK)
+
+ MID:
+
+ ee96cc5f18e14f6894e2775c546240d8
+ UID:
+
+ SDOC-SSS-86
+ STATUS:
+
+ Active
+ STATEMENT:
+
+
+
+ The Requirements Tool shall provide a Software Development Kit (SDK) that allows customization of the
+ Requirements Tool functions.
+ NOTE: An SDK provides access to the API of the Requirements Tool. Examples of functions that may be
+ used by the users of the tool:
+
+ - Custom import/export functions to/from various requirements/documentation formats.
+ - Implement custom visualization functions.
+ - Implement integration with other tools.
+
+
+
+ RATIONALE:
+
+
+
+ A SDK allows a software engineer to extend the Requirements Tool capabilities.
+
+
+ RELATIONS (Child):
+
+
+
+
+
+
+
+
+
+
+
+ 10.10. Programmatic access to requirements data
+
+ MID:
+
+ f4b122c5081f4b218aa93a119e372a34
+ UID:
+
+ SDOC-SSS-87
+ STATUS:
+
+ Active
+ STATEMENT:
+
+
+
+ The Requirements Tool shall provide programmatic access to requirements data.
+
+
+ RATIONALE:
+
+
+
+ When the requirements data is accessible by a user directly, it is possible to exchange the data or
+ implement additional scripting procedures.
+
+
+ RELATIONS (Child):
+
+
+
+
+
+
+
+
+
+
+
+
+ 11. Implementation suggestions
+
+
+
+ MID:
+
+ 29fa83c59e714d0da8b36a9dc65b0c72
+ UID:
+
+ SECTION-SSSS-Implementation-suggestions
+
+
+
+
+
+
+
+
+
+ 11.1. Static HTML export
+
+ MID:
+
+ 3db06eb066b4441290e06b08405da0a9
+ UID:
+
+ SDOC-SSS-30
+ STATUS:
+
+ Active
+ STATEMENT:
+
+
+
+ The Requirements Tool shall support generation of documentation to static HTML.
+
+
+ RATIONALE:
+
+
+
+ A static HTML export capability enables:
+
+ - Viewing requirements in browsers without any additional software.
+ - Exchanging HTML content as zip between users.
+ - Publishing HTML content via static website hosting providers (GitHub and GitLab Pages, Read the
+ Docs, Heroku, etc.).
+
+
+
+ RELATIONS (Child):
+
+
+
+
+
+
+
+
+
+
+
+ 11.2. Graphical user interface (GUI)
+
+ MID:
+
+ e718af582b0345c2b0ddb6e405cb6d9a
+ UID:
+
+ SDOC-SSS-31
+ STATUS:
+
+ Active
+ STATEMENT:
+
+
+
+ The Requirements Tool shall provide a graphical user interface.
+
+
+ RELATIONS (Child):
+
+
+
+
+
+
+
+
+
+
+
+ 11.3. Command-line interface
+
+ MID:
+
+ cd20e9613a65441a8862143ba6407f61
+ UID:
+
+ SDOC-SSS-32
+ STATUS:
+
+ Active
+ STATEMENT:
+
+
+
+ The Requirements Tool shall provide a command line interface (CLI).
+
+
+ RELATIONS (Child):
+
+
+
+
+
+
+
+
+
+
+
+ 11.4. Web API interface
+
+ MID:
+
+ 4475857729e5476cbbb409cc844048fd
+ UID:
+
+ SDOC-SSS-68
+ STATUS:
+
+ Active
+ STATEMENT:
+
+
+
+ The Requirements Tool shall provide an API interface.
+
+
+ RELATIONS (Child):
+
+
+
+
+
+
+
+
+
+
+
+ 11.5. Version control (Git)
+
+ MID:
+
+ 5ac2f3010db84466bff854fc323e944c
+ UID:
+
+ SDOC-SSS-33
+ STATUS:
+
+ Active
+ STATEMENT:
+
+
+
+ The Requirements Tool shall support the software version control systems (e.g., Git).
+
+
+ RATIONALE:
+
+
+
+
+ - Git allows precise tracking of the changes to the documentation.
+ - Requirements/documentation content can be release-tagged.
+ - The "Time machine" function: ability to review the older state of the documentation/requirements
+ tree.
+
+
+
+ RELATIONS (Child):
+
+
+
+
+
+
+
+
+
+
+
+ 11.6. Support major operating systems
+
+ MID:
+
+ b76fb774542849a182e2cdd89fdaab3c
+ UID:
+
+ SDOC-SSS-67
+ STATUS:
+
+ Active
+ STATEMENT:
+
+
+
+ The Requirements Tool shall support at least the following operating systems:
+
+ - Linux
+ - Windows
+ - macOS.
+
+
+
+ RELATIONS (Child):
+
+
+
+
+
+
+
+
+
+
+
+ 11.7. Conservative languages for implementation
+
+ MID:
+
+ 871a7a66eb50436997fde692e90e93eb
+ UID:
+
+ SDOC-SSS-69
+ STATUS:
+
+ Active
+ STATEMENT:
+
+
+
+ The Requirements Tool shall be implemented using the popular programming languages.
+ NOTE: Examples of the most popular programming languages:
+
+ - Java
+ - C++
+ - Python
+ - JavaScript
+
+
+
+ RATIONALE:
+
+
+
+ Choosing a less popular programming language can limit the long-term maintainability of the tool.
+
+
+ COMMENT:
+
+
+
+ Examples of less popular programming languages, with all due respect to their powerful features:
+ Haskell, F#, Ada, etc.
+
+
+ RELATIONS (Child):
+
+
+
+
+
+
+
+
+
+
+
+ 11.8. Long-term maintainability of a tool
+
+ MID:
+
+ 0556a0b2773d4ee0b44b22773455a600
+ UID:
+
+ SDOC-SSS-90
+ STATUS:
+
+ Active
+ STATEMENT:
+
+
+
+ The Requirements Tool shall be designed for long-term maintenance.
+ NOTE: Long-term maintenance aspects to consider:
+
+ - Careful selection of the technologies used, e.g., avoid building on too many unrelated technologies
+ at the same time.
+ - Take into account the existing experience of the development team. Consider the availability of
+ qualified developers in the future.
+ - Take into account maintainability by the development team as well as the users, e.g., IT/DevOps
+ department.
+
+
+
+ RELATIONS (Child):
+
+
+
+
+
+
+
+
+
+
+
+
+ 12. Text-based requirements language (optional)
+
+
+
+ MID:
+
+ 7bdea1a7cb9e4f6fbcf8497670f87278
+ UID:
+
+ SECTION-RTS-Text-based-requirements-language
+
+
+
+
+
+
+
+ STATEMENT:
+
+
+
+ Note: Not all requirements tools must be text-based. But when they are, the
+ following requirements apply.
+
+
+
+
+
+
+
+
+
+
+ 12.1. Text files for storing documentation and requirements
+
+ MID:
+
+ f472e85f3398413795234a9298d4af3c
+ UID:
+
+ SDOC-SSS-88
+ STATUS:
+
+ Active
+ STATEMENT:
+
+
+
+ The Requirements Tool shall allow storage of documentation and requirements content using text files.
+
+
+
+ RELATIONS (Child):
+
+
+
+
+
+
+
+
+
+
+
+ 12.2. Strict text language syntax
+
+ MID:
+
+ b13bc3dfa7324f238bc06a88baf5edb6
+ UID:
+
+ SDOC-SSS-55
+ STATUS:
+
+ Active
+ STATEMENT:
+
+
+
+ The Requirements Tool shall provide a strict syntax for its text language.
+
+
+ RELATIONS (Child):
+
+
+
+
+
+
+
+
+
+
+
+ 12.3. Machine-readable format
+
+ MID:
+
+ 0b47da74f9ec45e6a77573185b95f327
+ UID:
+
+ SDOC-SSS-54
+ STATUS:
+
+ Active
+ STATEMENT:
+
+
+
+ The Requirement Tool's text language shall be machine-readable.
+
+
+ RELATIONS (Parent):
+
+
+
+ RELATIONS (Child):
+
+
+
+
+
+
+
+
+
+
+
+ 12.4. Requirements data from multiple repositories
+
+ MID:
+
+ 13f3e7765b494237893c1585a7c9dfd0
+ UID:
+
+ SDOC-SSS-34
+ STATUS:
+
+ Active
+ STATEMENT:
+
+
+
+ The Requirement Tool shall allow reading requirements files from multiple folders or repositories.
+ NOTE: The folders/repositories can be arbitrarily nested.
+
+
+ RELATIONS (Child):
+
+
+
+
+
+
+
+
+
+
+
+
+ 13. Collaboration on requirements
+
+
+
+ MID:
+
+ efaa3e91045c4d49a70232f09a85ad35
+ UID:
+
+ SECTION-RTS-Requirements-collaboration
+
+
+
+
+
+
+
+
+
+ 13.1. Support user accounts
+
+ MID:
+
+ f9d65df46ff24b0da6cb2bf011f0fc70
+ UID:
+
+ SDOC-SSS-65
+ STATUS:
+
+ Draft
+ RELATIONS (Child):
+
+
+
+
+
+
+
+
+
+
+
+ 13.2. Send notifications about updated requirements
+
+ MID:
+
+ 29d0374556494f38977ec3c928aa894d
+ UID:
+
+ SDOC-SSS-66
+ STATUS:
+
+ Draft
+ RELATIONS (Child):
+
+
+
+
+
+
+
+
+
+
+
+
+ 14. Development process
+
+
+
+ MID:
+
+ f80a4b7ff03042849c3814c6cd5e5ca4
+ UID:
+
+ SECTION-SSSS-Development-process
+
+
+
+
+
+
+
+
+
+ 14.1. Requirements engineering
+
+ MID:
+
+ f16ea50f686e412f9c21d8096055bb47
+ UID:
+
+ SDOC-SSS-76
+ STATUS:
+
+ Active
+ STATEMENT:
+
+
+
+ The Requirements Tool's development process shall include the Requirements Tool's own requirements
+ engineering.
+
+
+ RATIONALE:
+
+
+
+ A requirements tool is not a trivial project. A clear set of requirements for the developed tool helps
+ to structure the development and communicate the functions of the tool to the developers and the users
+ of the tool.
+
+
+ RELATIONS (Child):
+
+
+
+
+
+
+
+
+
+
+
+ 14.2. Self-hosted requirements
+
+ MID:
+
+ 0bebdf77108a499c87e5c0838204c39c
+ UID:
+
+ SDOC-SSS-50
+ STATUS:
+
+ Active
+ STATEMENT:
+
+
+
+ The Requirements Tool's requirements shall be developed and stored using the Requirements Tool itself.
+
+
+
+ RATIONALE:
+
+
+
+ While not strictly necessary, developing the requirements for the tool using the tool itself aids
+ developers in test-driving its functionality during the requirement development phase. Moreover, having
+ the tool host its own requirements provides a tangible and dynamic illustration of how the tool can be
+ employed for crafting requirements documentation.
+
+
+ RELATIONS (Parent):
+
+
+
+ RELATIONS (Child):
+
+
+
+
+
+
+
+
+
+
+
+ 14.3. Test coverage
+
+ MID:
+
+ 1a39a758930040029db320d8466806c1
+ UID:
+
+ SDOC-SSS-77
+ STATUS:
+
+ Active
+ STATEMENT:
+
+
+
+ The Requirements Tool's development process shall ensure:
+
+ - A testability of the tool.
+ - The highest possible coverage of the tool's code by test.
+ - Usage of modern testing methods to ensure adequate coverage of the tool's functions (e.g.,
+ command-line interface, web interface, smallest units of code, etc.).
+
+
+
+ RATIONALE:
+
+
+
+ The presence of tests, the adequate selection of test methods and a high test coverage are
+ preconditions for a high quality of the requirements tool.
+
+
+ RELATIONS (Child):
+
+
+
+
+
+
+
+
+
+
+
+ 14.4. Tool qualification
+
+ MID:
+
+ 8cb5ac6812924f4c8f4afd156b2f021c
+ UID:
+
+ SDOC-SSS-78
+ STATUS:
+
+ Active
+ STATEMENT:
+
+
+
+ The Requirements Tool's development process shall ensure that the tool can be qualified for the use in
+ critical product developments as required by the rigorous technical standards (e.g., EN IEC 61508).
+
+
+ RATIONALE:
+
+
+
+ Many project developments require a qualification of the tools used during the development. A
+ requirements tool is one of the critical tools that affect the project development. If a requirement
+ tool is developed to the higher standards of quality, it simplifies the argument of bringing the tool
+ forward and using it in a particular project.
+
+
+ RELATIONS (Child):
+
+
+
+
+
+
+
+
+
+
+
+
+ 15. Licensing and distribution
+
+
+
+ MID:
+
+ e4cd429e9ec04deabfd1fb1381c39e38
+ UID:
+
+ SECTION-SSSS-Licensing-and-distribution
+
+
+
+
+
+
+
+ STATEMENT:
+
+
+
+ This section outlines the requirements for the "free and open source" aspect of the Requirements Tool.
+
+
+
+
+
+
+
+
+
+
+
+ 15.1. Open source
+
+ MID:
+
+ 2f30b94fdc074c8fa5858dfccc6202e8
+ UID:
+
+ SDOC-SSS-38
+ STATUS:
+
+ Active
+ STATEMENT:
+
+
+
+ The Requirements Tool's source code shall be publicly available, e.g., hosted on a code hosting
+ platform such as GitHub or GitLab.
+
+
+ RELATIONS (Child):
+
+
+
+
+
+
+
+
+
+
+
+ 15.2. Only open source dependencies
+
+ MID:
+
+ 27b640de8cae44a680b23429c981bee9
+ UID:
+
+ SDOC-SSS-39
+ STATUS:
+
+ Active
+ STATEMENT:
+
+
+
+ The Requirement Tool's source code shall be based on open source software components.
+
+
+ RELATIONS (Child):
+
+
+
+
+
+
+
+
+
+
+
+ 15.3. Free
+
+ MID:
+
+ 1338faad11204073a97212fa0fd11317
+ UID:
+
+ SDOC-SSS-40
+ STATUS:
+
+ Active
+ STATEMENT:
+
+
+
+ The Requirements Tool shall be licensed under a permissive license, ensuring no/minimal constraints on
+ the utilization and dissemination of the project.
+ NOTE: Example of a permissive license: MIT, Apache 2.
+
+
+ RATIONALE:
+
+
+
+ This requirement captures the essence of an open and free requirements management tool.
+
+
+ RELATIONS (Child):
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Requirements Tool Specification (L1)
+
+
+
+
+ VERSION:
+
+
+ Git commit: 0.15.0-28-gbbad5d7fa, Git branch: mettta/html2pdf_strict_assertsDATE:
+
+
+ 2025-11-20 23:38:21
+
+
+
+
+
+
+
+
+
+ /
+
+
+
+
+
+
+
+
+
+
+ |