+
+ Read the Docs
+ v: ${config.versions.current.slug}
+
+
+
+
+ ${renderLanguages(config)}
+ ${renderVersions(config)}
+ ${renderDownloads(config)}
+
+ On Read the Docs
+
+ Project Home
+
+
+ Builds
+
+
+ Downloads
+
+
+
+ Search
+
+
+
+
+
+
+ Hosted by Read the Docs
+
+
+
+ `;
+
+ // Inject the generated flyout into the body HTML element.
+ document.body.insertAdjacentHTML("beforeend", flyout);
+
+ // Trigger the Read the Docs Addons Search modal when clicking on the "Search docs" input from inside the flyout.
+ document
+ .querySelector("#flyout-search-form")
+ .addEventListener("focusin", () => {
+ const event = new CustomEvent("readthedocs-search-show");
+ document.dispatchEvent(event);
+ });
+ })
+}
+
+if (themeLanguageSelector || themeVersionSelector) {
+ function onSelectorSwitch(event) {
+ const option = event.target.selectedIndex;
+ const item = event.target.options[option];
+ window.location.href = item.dataset.url;
+ }
+
+ document.addEventListener("readthedocs-addons-data-ready", function (event) {
+ const config = event.detail.data();
+
+ const versionSwitch = document.querySelector(
+ "div.switch-menus > div.version-switch",
+ );
+ if (themeVersionSelector) {
+ let versions = config.versions.active;
+ if (config.versions.current.hidden || config.versions.current.type === "external") {
+ versions.unshift(config.versions.current);
+ }
+ const versionSelect = `
+
+ ${versions
+ .map(
+ (version) => `
+
+ ${version.slug}
+ `,
+ )
+ .join("\n")}
+
+ `;
+
+ versionSwitch.innerHTML = versionSelect;
+ versionSwitch.firstElementChild.addEventListener("change", onSelectorSwitch);
+ }
+
+ const languageSwitch = document.querySelector(
+ "div.switch-menus > div.language-switch",
+ );
+
+ if (themeLanguageSelector) {
+ if (config.projects.translations.length) {
+ // Add the current language to the options on the selector
+ let languages = config.projects.translations.concat(
+ config.projects.current,
+ );
+ languages = languages.sort((a, b) =>
+ a.language.name.localeCompare(b.language.name),
+ );
+
+ const languageSelect = `
+
+ ${languages
+ .map(
+ (language) => `
+
+ ${language.language.name}
+ `,
+ )
+ .join("\n")}
+
+ `;
+
+ languageSwitch.innerHTML = languageSelect;
+ languageSwitch.firstElementChild.addEventListener("change", onSelectorSwitch);
+ }
+ else {
+ languageSwitch.remove();
+ }
+ }
+ });
+}
+
+document.addEventListener("readthedocs-addons-data-ready", function (event) {
+ // Trigger the Read the Docs Addons Search modal when clicking on "Search docs" input from the topnav.
+ document
+ .querySelector("[role='search'] input")
+ .addEventListener("focusin", () => {
+ const event = new CustomEvent("readthedocs-search-show");
+ document.dispatchEvent(event);
+ });
+});
\ No newline at end of file
diff --git a/_static/language_data.js b/_static/language_data.js
new file mode 100644
index 0000000..c7fe6c6
--- /dev/null
+++ b/_static/language_data.js
@@ -0,0 +1,192 @@
+/*
+ * This script contains the language-specific data used by searchtools.js,
+ * namely the list of stopwords, stemmer, scorer and splitter.
+ */
+
+var stopwords = ["a", "and", "are", "as", "at", "be", "but", "by", "for", "if", "in", "into", "is", "it", "near", "no", "not", "of", "on", "or", "such", "that", "the", "their", "then", "there", "these", "they", "this", "to", "was", "will", "with"];
+
+
+/* Non-minified version is copied as a separate JS file, if available */
+
+/**
+ * Porter Stemmer
+ */
+var Stemmer = function() {
+
+ var step2list = {
+ ational: 'ate',
+ tional: 'tion',
+ enci: 'ence',
+ anci: 'ance',
+ izer: 'ize',
+ bli: 'ble',
+ alli: 'al',
+ entli: 'ent',
+ eli: 'e',
+ ousli: 'ous',
+ ization: 'ize',
+ ation: 'ate',
+ ator: 'ate',
+ alism: 'al',
+ iveness: 'ive',
+ fulness: 'ful',
+ ousness: 'ous',
+ aliti: 'al',
+ iviti: 'ive',
+ biliti: 'ble',
+ logi: 'log'
+ };
+
+ var step3list = {
+ icate: 'ic',
+ ative: '',
+ alize: 'al',
+ iciti: 'ic',
+ ical: 'ic',
+ ful: '',
+ ness: ''
+ };
+
+ var c = "[^aeiou]"; // consonant
+ var v = "[aeiouy]"; // vowel
+ var C = c + "[^aeiouy]*"; // consonant sequence
+ var V = v + "[aeiou]*"; // vowel sequence
+
+ var mgr0 = "^(" + C + ")?" + V + C; // [C]VC... is m>0
+ var meq1 = "^(" + C + ")?" + V + C + "(" + V + ")?$"; // [C]VC[V] is m=1
+ var mgr1 = "^(" + C + ")?" + V + C + V + C; // [C]VCVC... is m>1
+ var s_v = "^(" + C + ")?" + v; // vowel in stem
+
+ this.stemWord = function (w) {
+ var stem;
+ var suffix;
+ var firstch;
+ var origword = w;
+
+ if (w.length < 3)
+ return w;
+
+ var re;
+ var re2;
+ var re3;
+ var re4;
+
+ firstch = w.substr(0,1);
+ if (firstch == "y")
+ w = firstch.toUpperCase() + w.substr(1);
+
+ // Step 1a
+ re = /^(.+?)(ss|i)es$/;
+ re2 = /^(.+?)([^s])s$/;
+
+ if (re.test(w))
+ w = w.replace(re,"$1$2");
+ else if (re2.test(w))
+ w = w.replace(re2,"$1$2");
+
+ // Step 1b
+ re = /^(.+?)eed$/;
+ re2 = /^(.+?)(ed|ing)$/;
+ if (re.test(w)) {
+ var fp = re.exec(w);
+ re = new RegExp(mgr0);
+ if (re.test(fp[1])) {
+ re = /.$/;
+ w = w.replace(re,"");
+ }
+ }
+ else if (re2.test(w)) {
+ var fp = re2.exec(w);
+ stem = fp[1];
+ re2 = new RegExp(s_v);
+ if (re2.test(stem)) {
+ w = stem;
+ re2 = /(at|bl|iz)$/;
+ re3 = new RegExp("([^aeiouylsz])\\1$");
+ re4 = new RegExp("^" + C + v + "[^aeiouwxy]$");
+ if (re2.test(w))
+ w = w + "e";
+ else if (re3.test(w)) {
+ re = /.$/;
+ w = w.replace(re,"");
+ }
+ else if (re4.test(w))
+ w = w + "e";
+ }
+ }
+
+ // Step 1c
+ re = /^(.+?)y$/;
+ if (re.test(w)) {
+ var fp = re.exec(w);
+ stem = fp[1];
+ re = new RegExp(s_v);
+ if (re.test(stem))
+ w = stem + "i";
+ }
+
+ // Step 2
+ re = /^(.+?)(ational|tional|enci|anci|izer|bli|alli|entli|eli|ousli|ization|ation|ator|alism|iveness|fulness|ousness|aliti|iviti|biliti|logi)$/;
+ if (re.test(w)) {
+ var fp = re.exec(w);
+ stem = fp[1];
+ suffix = fp[2];
+ re = new RegExp(mgr0);
+ if (re.test(stem))
+ w = stem + step2list[suffix];
+ }
+
+ // Step 3
+ re = /^(.+?)(icate|ative|alize|iciti|ical|ful|ness)$/;
+ if (re.test(w)) {
+ var fp = re.exec(w);
+ stem = fp[1];
+ suffix = fp[2];
+ re = new RegExp(mgr0);
+ if (re.test(stem))
+ w = stem + step3list[suffix];
+ }
+
+ // Step 4
+ re = /^(.+?)(al|ance|ence|er|ic|able|ible|ant|ement|ment|ent|ou|ism|ate|iti|ous|ive|ize)$/;
+ re2 = /^(.+?)(s|t)(ion)$/;
+ if (re.test(w)) {
+ var fp = re.exec(w);
+ stem = fp[1];
+ re = new RegExp(mgr1);
+ if (re.test(stem))
+ w = stem;
+ }
+ else if (re2.test(w)) {
+ var fp = re2.exec(w);
+ stem = fp[1] + fp[2];
+ re2 = new RegExp(mgr1);
+ if (re2.test(stem))
+ w = stem;
+ }
+
+ // Step 5
+ re = /^(.+?)e$/;
+ if (re.test(w)) {
+ var fp = re.exec(w);
+ stem = fp[1];
+ re = new RegExp(mgr1);
+ re2 = new RegExp(meq1);
+ re3 = new RegExp("^" + C + v + "[^aeiouwxy]$");
+ if (re.test(stem) || (re2.test(stem) && !(re3.test(stem))))
+ w = stem;
+ }
+ re = /ll$/;
+ re2 = new RegExp(mgr1);
+ if (re.test(w) && re2.test(w)) {
+ re = /.$/;
+ w = w.replace(re,"");
+ }
+
+ // and turn initial Y back to y
+ if (firstch == "y")
+ w = firstch.toLowerCase() + w.substr(1);
+ return w;
+ }
+}
+
diff --git a/_static/logo.svg b/_static/logo.svg
new file mode 100644
index 0000000..77896ed
--- /dev/null
+++ b/_static/logo.svg
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/_static/minus.png b/_static/minus.png
new file mode 100644
index 0000000..d96755f
Binary files /dev/null and b/_static/minus.png differ
diff --git a/_static/plus.png b/_static/plus.png
new file mode 100644
index 0000000..7107cec
Binary files /dev/null and b/_static/plus.png differ
diff --git a/_static/pygments.css b/_static/pygments.css
new file mode 100644
index 0000000..3f7c128
--- /dev/null
+++ b/_static/pygments.css
@@ -0,0 +1,75 @@
+pre { line-height: 125%; }
+td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
+span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
+td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
+span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
+.highlight .hll { background-color: #ffffcc }
+.highlight { background: #f0f3f3; }
+.highlight .c { color: #0099FF; font-style: italic } /* Comment */
+.highlight .err { color: #AA0000; background-color: #FFAAAA } /* Error */
+.highlight .k { color: #006699; font-weight: bold } /* Keyword */
+.highlight .o { color: #555555 } /* Operator */
+.highlight .ch { color: #0099FF; font-style: italic } /* Comment.Hashbang */
+.highlight .cm { color: #0099FF; font-style: italic } /* Comment.Multiline */
+.highlight .cp { color: #009999 } /* Comment.Preproc */
+.highlight .cpf { color: #0099FF; font-style: italic } /* Comment.PreprocFile */
+.highlight .c1 { color: #0099FF; font-style: italic } /* Comment.Single */
+.highlight .cs { color: #0099FF; font-weight: bold; font-style: italic } /* Comment.Special */
+.highlight .gd { background-color: #FFCCCC; border: 1px solid #CC0000 } /* Generic.Deleted */
+.highlight .ge { font-style: italic } /* Generic.Emph */
+.highlight .ges { font-weight: bold; font-style: italic } /* Generic.EmphStrong */
+.highlight .gr { color: #FF0000 } /* Generic.Error */
+.highlight .gh { color: #003300; font-weight: bold } /* Generic.Heading */
+.highlight .gi { background-color: #CCFFCC; border: 1px solid #00CC00 } /* Generic.Inserted */
+.highlight .go { color: #AAAAAA } /* Generic.Output */
+.highlight .gp { color: #000099; font-weight: bold } /* Generic.Prompt */
+.highlight .gs { font-weight: bold } /* Generic.Strong */
+.highlight .gu { color: #003300; font-weight: bold } /* Generic.Subheading */
+.highlight .gt { color: #99CC66 } /* Generic.Traceback */
+.highlight .kc { color: #006699; font-weight: bold } /* Keyword.Constant */
+.highlight .kd { color: #006699; font-weight: bold } /* Keyword.Declaration */
+.highlight .kn { color: #006699; font-weight: bold } /* Keyword.Namespace */
+.highlight .kp { color: #006699 } /* Keyword.Pseudo */
+.highlight .kr { color: #006699; font-weight: bold } /* Keyword.Reserved */
+.highlight .kt { color: #007788; font-weight: bold } /* Keyword.Type */
+.highlight .m { color: #FF6600 } /* Literal.Number */
+.highlight .s { color: #CC3300 } /* Literal.String */
+.highlight .na { color: #330099 } /* Name.Attribute */
+.highlight .nb { color: #336666 } /* Name.Builtin */
+.highlight .nc { color: #00AA88; font-weight: bold } /* Name.Class */
+.highlight .no { color: #336600 } /* Name.Constant */
+.highlight .nd { color: #9999FF } /* Name.Decorator */
+.highlight .ni { color: #999999; font-weight: bold } /* Name.Entity */
+.highlight .ne { color: #CC0000; font-weight: bold } /* Name.Exception */
+.highlight .nf { color: #CC00FF } /* Name.Function */
+.highlight .nl { color: #9999FF } /* Name.Label */
+.highlight .nn { color: #00CCFF; font-weight: bold } /* Name.Namespace */
+.highlight .nt { color: #330099; font-weight: bold } /* Name.Tag */
+.highlight .nv { color: #003333 } /* Name.Variable */
+.highlight .ow { color: #000000; font-weight: bold } /* Operator.Word */
+.highlight .w { color: #bbbbbb } /* Text.Whitespace */
+.highlight .mb { color: #FF6600 } /* Literal.Number.Bin */
+.highlight .mf { color: #FF6600 } /* Literal.Number.Float */
+.highlight .mh { color: #FF6600 } /* Literal.Number.Hex */
+.highlight .mi { color: #FF6600 } /* Literal.Number.Integer */
+.highlight .mo { color: #FF6600 } /* Literal.Number.Oct */
+.highlight .sa { color: #CC3300 } /* Literal.String.Affix */
+.highlight .sb { color: #CC3300 } /* Literal.String.Backtick */
+.highlight .sc { color: #CC3300 } /* Literal.String.Char */
+.highlight .dl { color: #CC3300 } /* Literal.String.Delimiter */
+.highlight .sd { color: #CC3300; font-style: italic } /* Literal.String.Doc */
+.highlight .s2 { color: #CC3300 } /* Literal.String.Double */
+.highlight .se { color: #CC3300; font-weight: bold } /* Literal.String.Escape */
+.highlight .sh { color: #CC3300 } /* Literal.String.Heredoc */
+.highlight .si { color: #AA0000 } /* Literal.String.Interpol */
+.highlight .sx { color: #CC3300 } /* Literal.String.Other */
+.highlight .sr { color: #33AAAA } /* Literal.String.Regex */
+.highlight .s1 { color: #CC3300 } /* Literal.String.Single */
+.highlight .ss { color: #FFCC33 } /* Literal.String.Symbol */
+.highlight .bp { color: #336666 } /* Name.Builtin.Pseudo */
+.highlight .fm { color: #CC00FF } /* Name.Function.Magic */
+.highlight .vc { color: #003333 } /* Name.Variable.Class */
+.highlight .vg { color: #003333 } /* Name.Variable.Global */
+.highlight .vi { color: #003333 } /* Name.Variable.Instance */
+.highlight .vm { color: #003333 } /* Name.Variable.Magic */
+.highlight .il { color: #FF6600 } /* Literal.Number.Integer.Long */
\ No newline at end of file
diff --git a/_static/searchtools.js b/_static/searchtools.js
new file mode 100644
index 0000000..2c774d1
--- /dev/null
+++ b/_static/searchtools.js
@@ -0,0 +1,632 @@
+/*
+ * Sphinx JavaScript utilities for the full-text search.
+ */
+"use strict";
+
+/**
+ * Simple result scoring code.
+ */
+if (typeof Scorer === "undefined") {
+ var Scorer = {
+ // Implement the following function to further tweak the score for each result
+ // The function takes a result array [docname, title, anchor, descr, score, filename]
+ // and returns the new score.
+ /*
+ score: result => {
+ const [docname, title, anchor, descr, score, filename, kind] = result
+ return score
+ },
+ */
+
+ // query matches the full name of an object
+ objNameMatch: 11,
+ // or matches in the last dotted part of the object name
+ objPartialMatch: 6,
+ // Additive scores depending on the priority of the object
+ objPrio: {
+ 0: 15, // used to be importantResults
+ 1: 5, // used to be objectResults
+ 2: -5, // used to be unimportantResults
+ },
+ // Used when the priority is not in the mapping.
+ objPrioDefault: 0,
+
+ // query found in title
+ title: 15,
+ partialTitle: 7,
+ // query found in terms
+ term: 5,
+ partialTerm: 2,
+ };
+}
+
+// Global search result kind enum, used by themes to style search results.
+class SearchResultKind {
+ static get index() { return "index"; }
+ static get object() { return "object"; }
+ static get text() { return "text"; }
+ static get title() { return "title"; }
+}
+
+const _removeChildren = (element) => {
+ while (element && element.lastChild) element.removeChild(element.lastChild);
+};
+
+/**
+ * See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#escaping
+ */
+const _escapeRegExp = (string) =>
+ string.replace(/[.*+\-?^${}()|[\]\\]/g, "\\$&"); // $& means the whole matched string
+
+const _displayItem = (item, searchTerms, highlightTerms) => {
+ const docBuilder = DOCUMENTATION_OPTIONS.BUILDER;
+ const docFileSuffix = DOCUMENTATION_OPTIONS.FILE_SUFFIX;
+ const docLinkSuffix = DOCUMENTATION_OPTIONS.LINK_SUFFIX;
+ const showSearchSummary = DOCUMENTATION_OPTIONS.SHOW_SEARCH_SUMMARY;
+ const contentRoot = document.documentElement.dataset.content_root;
+
+ const [docName, title, anchor, descr, score, _filename, kind] = item;
+
+ let listItem = document.createElement("li");
+ // Add a class representing the item's type:
+ // can be used by a theme's CSS selector for styling
+ // See SearchResultKind for the class names.
+ listItem.classList.add(`kind-${kind}`);
+ let requestUrl;
+ let linkUrl;
+ if (docBuilder === "dirhtml") {
+ // dirhtml builder
+ let dirname = docName + "/";
+ if (dirname.match(/\/index\/$/))
+ dirname = dirname.substring(0, dirname.length - 6);
+ else if (dirname === "index/") dirname = "";
+ requestUrl = contentRoot + dirname;
+ linkUrl = requestUrl;
+ } else {
+ // normal html builders
+ requestUrl = contentRoot + docName + docFileSuffix;
+ linkUrl = docName + docLinkSuffix;
+ }
+ let linkEl = listItem.appendChild(document.createElement("a"));
+ linkEl.href = linkUrl + anchor;
+ linkEl.dataset.score = score;
+ linkEl.innerHTML = title;
+ if (descr) {
+ listItem.appendChild(document.createElement("span")).innerHTML =
+ " (" + descr + ")";
+ // highlight search terms in the description
+ if (SPHINX_HIGHLIGHT_ENABLED) // set in sphinx_highlight.js
+ highlightTerms.forEach((term) => _highlightText(listItem, term, "highlighted"));
+ }
+ else if (showSearchSummary)
+ fetch(requestUrl)
+ .then((responseData) => responseData.text())
+ .then((data) => {
+ if (data)
+ listItem.appendChild(
+ Search.makeSearchSummary(data, searchTerms, anchor)
+ );
+ // highlight search terms in the summary
+ if (SPHINX_HIGHLIGHT_ENABLED) // set in sphinx_highlight.js
+ highlightTerms.forEach((term) => _highlightText(listItem, term, "highlighted"));
+ });
+ Search.output.appendChild(listItem);
+};
+const _finishSearch = (resultCount) => {
+ Search.stopPulse();
+ Search.title.innerText = _("Search Results");
+ if (!resultCount)
+ Search.status.innerText = Documentation.gettext(
+ "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories."
+ );
+ else
+ Search.status.innerText = Documentation.ngettext(
+ "Search finished, found one page matching the search query.",
+ "Search finished, found ${resultCount} pages matching the search query.",
+ resultCount,
+ ).replace('${resultCount}', resultCount);
+};
+const _displayNextItem = (
+ results,
+ resultCount,
+ searchTerms,
+ highlightTerms,
+) => {
+ // results left, load the summary and display it
+ // this is intended to be dynamic (don't sub resultsCount)
+ if (results.length) {
+ _displayItem(results.pop(), searchTerms, highlightTerms);
+ setTimeout(
+ () => _displayNextItem(results, resultCount, searchTerms, highlightTerms),
+ 5
+ );
+ }
+ // search finished, update title and status message
+ else _finishSearch(resultCount);
+};
+// Helper function used by query() to order search results.
+// Each input is an array of [docname, title, anchor, descr, score, filename, kind].
+// Order the results by score (in opposite order of appearance, since the
+// `_displayNextItem` function uses pop() to retrieve items) and then alphabetically.
+const _orderResultsByScoreThenName = (a, b) => {
+ const leftScore = a[4];
+ const rightScore = b[4];
+ if (leftScore === rightScore) {
+ // same score: sort alphabetically
+ const leftTitle = a[1].toLowerCase();
+ const rightTitle = b[1].toLowerCase();
+ if (leftTitle === rightTitle) return 0;
+ return leftTitle > rightTitle ? -1 : 1; // inverted is intentional
+ }
+ return leftScore > rightScore ? 1 : -1;
+};
+
+/**
+ * Default splitQuery function. Can be overridden in ``sphinx.search`` with a
+ * custom function per language.
+ *
+ * The regular expression works by splitting the string on consecutive characters
+ * that are not Unicode letters, numbers, underscores, or emoji characters.
+ * This is the same as ``\W+`` in Python, preserving the surrogate pair area.
+ */
+if (typeof splitQuery === "undefined") {
+ var splitQuery = (query) => query
+ .split(/[^\p{Letter}\p{Number}_\p{Emoji_Presentation}]+/gu)
+ .filter(term => term) // remove remaining empty strings
+}
+
+/**
+ * Search Module
+ */
+const Search = {
+ _index: null,
+ _queued_query: null,
+ _pulse_status: -1,
+
+ htmlToText: (htmlString, anchor) => {
+ const htmlElement = new DOMParser().parseFromString(htmlString, 'text/html');
+ for (const removalQuery of [".headerlink", "script", "style"]) {
+ htmlElement.querySelectorAll(removalQuery).forEach((el) => { el.remove() });
+ }
+ if (anchor) {
+ const anchorContent = htmlElement.querySelector(`[role="main"] ${anchor}`);
+ if (anchorContent) return anchorContent.textContent;
+
+ console.warn(
+ `Anchored content block not found. Sphinx search tries to obtain it via DOM query '[role=main] ${anchor}'. Check your theme or template.`
+ );
+ }
+
+ // if anchor not specified or not found, fall back to main content
+ const docContent = htmlElement.querySelector('[role="main"]');
+ if (docContent) return docContent.textContent;
+
+ console.warn(
+ "Content block not found. Sphinx search tries to obtain it via DOM query '[role=main]'. Check your theme or template."
+ );
+ return "";
+ },
+
+ init: () => {
+ const query = new URLSearchParams(window.location.search).get("q");
+ document
+ .querySelectorAll('input[name="q"]')
+ .forEach((el) => (el.value = query));
+ if (query) Search.performSearch(query);
+ },
+
+ loadIndex: (url) =>
+ (document.body.appendChild(document.createElement("script")).src = url),
+
+ setIndex: (index) => {
+ Search._index = index;
+ if (Search._queued_query !== null) {
+ const query = Search._queued_query;
+ Search._queued_query = null;
+ Search.query(query);
+ }
+ },
+
+ hasIndex: () => Search._index !== null,
+
+ deferQuery: (query) => (Search._queued_query = query),
+
+ stopPulse: () => (Search._pulse_status = -1),
+
+ startPulse: () => {
+ if (Search._pulse_status >= 0) return;
+
+ const pulse = () => {
+ Search._pulse_status = (Search._pulse_status + 1) % 4;
+ Search.dots.innerText = ".".repeat(Search._pulse_status);
+ if (Search._pulse_status >= 0) window.setTimeout(pulse, 500);
+ };
+ pulse();
+ },
+
+ /**
+ * perform a search for something (or wait until index is loaded)
+ */
+ performSearch: (query) => {
+ // create the required interface elements
+ const searchText = document.createElement("h2");
+ searchText.textContent = _("Searching");
+ const searchSummary = document.createElement("p");
+ searchSummary.classList.add("search-summary");
+ searchSummary.innerText = "";
+ const searchList = document.createElement("ul");
+ searchList.setAttribute("role", "list");
+ searchList.classList.add("search");
+
+ const out = document.getElementById("search-results");
+ Search.title = out.appendChild(searchText);
+ Search.dots = Search.title.appendChild(document.createElement("span"));
+ Search.status = out.appendChild(searchSummary);
+ Search.output = out.appendChild(searchList);
+
+ const searchProgress = document.getElementById("search-progress");
+ // Some themes don't use the search progress node
+ if (searchProgress) {
+ searchProgress.innerText = _("Preparing search...");
+ }
+ Search.startPulse();
+
+ // index already loaded, the browser was quick!
+ if (Search.hasIndex()) Search.query(query);
+ else Search.deferQuery(query);
+ },
+
+ _parseQuery: (query) => {
+ // stem the search terms and add them to the correct list
+ const stemmer = new Stemmer();
+ const searchTerms = new Set();
+ const excludedTerms = new Set();
+ const highlightTerms = new Set();
+ const objectTerms = new Set(splitQuery(query.toLowerCase().trim()));
+ splitQuery(query.trim()).forEach((queryTerm) => {
+ const queryTermLower = queryTerm.toLowerCase();
+
+ // maybe skip this "word"
+ // stopwords array is from language_data.js
+ if (
+ stopwords.indexOf(queryTermLower) !== -1 ||
+ queryTerm.match(/^\d+$/)
+ )
+ return;
+
+ // stem the word
+ let word = stemmer.stemWord(queryTermLower);
+ // select the correct list
+ if (word[0] === "-") excludedTerms.add(word.substr(1));
+ else {
+ searchTerms.add(word);
+ highlightTerms.add(queryTermLower);
+ }
+ });
+
+ if (SPHINX_HIGHLIGHT_ENABLED) { // set in sphinx_highlight.js
+ localStorage.setItem("sphinx_highlight_terms", [...highlightTerms].join(" "))
+ }
+
+ // console.debug("SEARCH: searching for:");
+ // console.info("required: ", [...searchTerms]);
+ // console.info("excluded: ", [...excludedTerms]);
+
+ return [query, searchTerms, excludedTerms, highlightTerms, objectTerms];
+ },
+
+ /**
+ * execute search (requires search index to be loaded)
+ */
+ _performSearch: (query, searchTerms, excludedTerms, highlightTerms, objectTerms) => {
+ const filenames = Search._index.filenames;
+ const docNames = Search._index.docnames;
+ const titles = Search._index.titles;
+ const allTitles = Search._index.alltitles;
+ const indexEntries = Search._index.indexentries;
+
+ // Collect multiple result groups to be sorted separately and then ordered.
+ // Each is an array of [docname, title, anchor, descr, score, filename, kind].
+ const normalResults = [];
+ const nonMainIndexResults = [];
+
+ _removeChildren(document.getElementById("search-progress"));
+
+ const queryLower = query.toLowerCase().trim();
+ for (const [title, foundTitles] of Object.entries(allTitles)) {
+ if (title.toLowerCase().trim().includes(queryLower) && (queryLower.length >= title.length/2)) {
+ for (const [file, id] of foundTitles) {
+ const score = Math.round(Scorer.title * queryLower.length / title.length);
+ const boost = titles[file] === title ? 1 : 0; // add a boost for document titles
+ normalResults.push([
+ docNames[file],
+ titles[file] !== title ? `${titles[file]} > ${title}` : title,
+ id !== null ? "#" + id : "",
+ null,
+ score + boost,
+ filenames[file],
+ SearchResultKind.title,
+ ]);
+ }
+ }
+ }
+
+ // search for explicit entries in index directives
+ for (const [entry, foundEntries] of Object.entries(indexEntries)) {
+ if (entry.includes(queryLower) && (queryLower.length >= entry.length/2)) {
+ for (const [file, id, isMain] of foundEntries) {
+ const score = Math.round(100 * queryLower.length / entry.length);
+ const result = [
+ docNames[file],
+ titles[file],
+ id ? "#" + id : "",
+ null,
+ score,
+ filenames[file],
+ SearchResultKind.index,
+ ];
+ if (isMain) {
+ normalResults.push(result);
+ } else {
+ nonMainIndexResults.push(result);
+ }
+ }
+ }
+ }
+
+ // lookup as object
+ objectTerms.forEach((term) =>
+ normalResults.push(...Search.performObjectSearch(term, objectTerms))
+ );
+
+ // lookup as search terms in fulltext
+ normalResults.push(...Search.performTermsSearch(searchTerms, excludedTerms));
+
+ // let the scorer override scores with a custom scoring function
+ if (Scorer.score) {
+ normalResults.forEach((item) => (item[4] = Scorer.score(item)));
+ nonMainIndexResults.forEach((item) => (item[4] = Scorer.score(item)));
+ }
+
+ // Sort each group of results by score and then alphabetically by name.
+ normalResults.sort(_orderResultsByScoreThenName);
+ nonMainIndexResults.sort(_orderResultsByScoreThenName);
+
+ // Combine the result groups in (reverse) order.
+ // Non-main index entries are typically arbitrary cross-references,
+ // so display them after other results.
+ let results = [...nonMainIndexResults, ...normalResults];
+
+ // remove duplicate search results
+ // note the reversing of results, so that in the case of duplicates, the highest-scoring entry is kept
+ let seen = new Set();
+ results = results.reverse().reduce((acc, result) => {
+ let resultStr = result.slice(0, 4).concat([result[5]]).map(v => String(v)).join(',');
+ if (!seen.has(resultStr)) {
+ acc.push(result);
+ seen.add(resultStr);
+ }
+ return acc;
+ }, []);
+
+ return results.reverse();
+ },
+
+ query: (query) => {
+ const [searchQuery, searchTerms, excludedTerms, highlightTerms, objectTerms] = Search._parseQuery(query);
+ const results = Search._performSearch(searchQuery, searchTerms, excludedTerms, highlightTerms, objectTerms);
+
+ // for debugging
+ //Search.lastresults = results.slice(); // a copy
+ // console.info("search results:", Search.lastresults);
+
+ // print the results
+ _displayNextItem(results, results.length, searchTerms, highlightTerms);
+ },
+
+ /**
+ * search for object names
+ */
+ performObjectSearch: (object, objectTerms) => {
+ const filenames = Search._index.filenames;
+ const docNames = Search._index.docnames;
+ const objects = Search._index.objects;
+ const objNames = Search._index.objnames;
+ const titles = Search._index.titles;
+
+ const results = [];
+
+ const objectSearchCallback = (prefix, match) => {
+ const name = match[4]
+ const fullname = (prefix ? prefix + "." : "") + name;
+ const fullnameLower = fullname.toLowerCase();
+ if (fullnameLower.indexOf(object) < 0) return;
+
+ let score = 0;
+ const parts = fullnameLower.split(".");
+
+ // check for different match types: exact matches of full name or
+ // "last name" (i.e. last dotted part)
+ if (fullnameLower === object || parts.slice(-1)[0] === object)
+ score += Scorer.objNameMatch;
+ else if (parts.slice(-1)[0].indexOf(object) > -1)
+ score += Scorer.objPartialMatch; // matches in last name
+
+ const objName = objNames[match[1]][2];
+ const title = titles[match[0]];
+
+ // If more than one term searched for, we require other words to be
+ // found in the name/title/description
+ const otherTerms = new Set(objectTerms);
+ otherTerms.delete(object);
+ if (otherTerms.size > 0) {
+ const haystack = `${prefix} ${name} ${objName} ${title}`.toLowerCase();
+ if (
+ [...otherTerms].some((otherTerm) => haystack.indexOf(otherTerm) < 0)
+ )
+ return;
+ }
+
+ let anchor = match[3];
+ if (anchor === "") anchor = fullname;
+ else if (anchor === "-") anchor = objNames[match[1]][1] + "-" + fullname;
+
+ const descr = objName + _(", in ") + title;
+
+ // add custom score for some objects according to scorer
+ if (Scorer.objPrio.hasOwnProperty(match[2]))
+ score += Scorer.objPrio[match[2]];
+ else score += Scorer.objPrioDefault;
+
+ results.push([
+ docNames[match[0]],
+ fullname,
+ "#" + anchor,
+ descr,
+ score,
+ filenames[match[0]],
+ SearchResultKind.object,
+ ]);
+ };
+ Object.keys(objects).forEach((prefix) =>
+ objects[prefix].forEach((array) =>
+ objectSearchCallback(prefix, array)
+ )
+ );
+ return results;
+ },
+
+ /**
+ * search for full-text terms in the index
+ */
+ performTermsSearch: (searchTerms, excludedTerms) => {
+ // prepare search
+ const terms = Search._index.terms;
+ const titleTerms = Search._index.titleterms;
+ const filenames = Search._index.filenames;
+ const docNames = Search._index.docnames;
+ const titles = Search._index.titles;
+
+ const scoreMap = new Map();
+ const fileMap = new Map();
+
+ // perform the search on the required terms
+ searchTerms.forEach((word) => {
+ const files = [];
+ const arr = [
+ { files: terms[word], score: Scorer.term },
+ { files: titleTerms[word], score: Scorer.title },
+ ];
+ // add support for partial matches
+ if (word.length > 2) {
+ const escapedWord = _escapeRegExp(word);
+ if (!terms.hasOwnProperty(word)) {
+ Object.keys(terms).forEach((term) => {
+ if (term.match(escapedWord))
+ arr.push({ files: terms[term], score: Scorer.partialTerm });
+ });
+ }
+ if (!titleTerms.hasOwnProperty(word)) {
+ Object.keys(titleTerms).forEach((term) => {
+ if (term.match(escapedWord))
+ arr.push({ files: titleTerms[term], score: Scorer.partialTitle });
+ });
+ }
+ }
+
+ // no match but word was a required one
+ if (arr.every((record) => record.files === undefined)) return;
+
+ // found search word in contents
+ arr.forEach((record) => {
+ if (record.files === undefined) return;
+
+ let recordFiles = record.files;
+ if (recordFiles.length === undefined) recordFiles = [recordFiles];
+ files.push(...recordFiles);
+
+ // set score for the word in each file
+ recordFiles.forEach((file) => {
+ if (!scoreMap.has(file)) scoreMap.set(file, {});
+ scoreMap.get(file)[word] = record.score;
+ });
+ });
+
+ // create the mapping
+ files.forEach((file) => {
+ if (!fileMap.has(file)) fileMap.set(file, [word]);
+ else if (fileMap.get(file).indexOf(word) === -1) fileMap.get(file).push(word);
+ });
+ });
+
+ // now check if the files don't contain excluded terms
+ const results = [];
+ for (const [file, wordList] of fileMap) {
+ // check if all requirements are matched
+
+ // as search terms with length < 3 are discarded
+ const filteredTermCount = [...searchTerms].filter(
+ (term) => term.length > 2
+ ).length;
+ if (
+ wordList.length !== searchTerms.size &&
+ wordList.length !== filteredTermCount
+ )
+ continue;
+
+ // ensure that none of the excluded terms is in the search result
+ if (
+ [...excludedTerms].some(
+ (term) =>
+ terms[term] === file ||
+ titleTerms[term] === file ||
+ (terms[term] || []).includes(file) ||
+ (titleTerms[term] || []).includes(file)
+ )
+ )
+ break;
+
+ // select one (max) score for the file.
+ const score = Math.max(...wordList.map((w) => scoreMap.get(file)[w]));
+ // add result to the result list
+ results.push([
+ docNames[file],
+ titles[file],
+ "",
+ null,
+ score,
+ filenames[file],
+ SearchResultKind.text,
+ ]);
+ }
+ return results;
+ },
+
+ /**
+ * helper function to return a node containing the
+ * search summary for a given text. keywords is a list
+ * of stemmed words.
+ */
+ makeSearchSummary: (htmlText, keywords, anchor) => {
+ const text = Search.htmlToText(htmlText, anchor);
+ if (text === "") return null;
+
+ const textLower = text.toLowerCase();
+ const actualStartPosition = [...keywords]
+ .map((k) => textLower.indexOf(k.toLowerCase()))
+ .filter((i) => i > -1)
+ .slice(-1)[0];
+ const startWithContext = Math.max(actualStartPosition - 120, 0);
+
+ const top = startWithContext === 0 ? "" : "...";
+ const tail = startWithContext + 240 < text.length ? "..." : "";
+
+ let summary = document.createElement("p");
+ summary.classList.add("context");
+ summary.textContent = top + text.substr(startWithContext, 240).trim() + tail;
+
+ return summary;
+ },
+};
+
+_ready(Search.init);
diff --git a/_static/sphinx-design.min.css b/_static/sphinx-design.min.css
new file mode 100644
index 0000000..860c36d
--- /dev/null
+++ b/_static/sphinx-design.min.css
@@ -0,0 +1 @@
+.sd-bg-primary{background-color:var(--sd-color-primary) !important}.sd-bg-text-primary{color:var(--sd-color-primary-text) !important}button.sd-bg-primary:focus,button.sd-bg-primary:hover{background-color:var(--sd-color-primary-highlight) !important}a.sd-bg-primary:focus,a.sd-bg-primary:hover{background-color:var(--sd-color-primary-highlight) !important}.sd-bg-secondary{background-color:var(--sd-color-secondary) !important}.sd-bg-text-secondary{color:var(--sd-color-secondary-text) !important}button.sd-bg-secondary:focus,button.sd-bg-secondary:hover{background-color:var(--sd-color-secondary-highlight) !important}a.sd-bg-secondary:focus,a.sd-bg-secondary:hover{background-color:var(--sd-color-secondary-highlight) !important}.sd-bg-success{background-color:var(--sd-color-success) !important}.sd-bg-text-success{color:var(--sd-color-success-text) !important}button.sd-bg-success:focus,button.sd-bg-success:hover{background-color:var(--sd-color-success-highlight) !important}a.sd-bg-success:focus,a.sd-bg-success:hover{background-color:var(--sd-color-success-highlight) !important}.sd-bg-info{background-color:var(--sd-color-info) !important}.sd-bg-text-info{color:var(--sd-color-info-text) !important}button.sd-bg-info:focus,button.sd-bg-info:hover{background-color:var(--sd-color-info-highlight) !important}a.sd-bg-info:focus,a.sd-bg-info:hover{background-color:var(--sd-color-info-highlight) !important}.sd-bg-warning{background-color:var(--sd-color-warning) !important}.sd-bg-text-warning{color:var(--sd-color-warning-text) !important}button.sd-bg-warning:focus,button.sd-bg-warning:hover{background-color:var(--sd-color-warning-highlight) !important}a.sd-bg-warning:focus,a.sd-bg-warning:hover{background-color:var(--sd-color-warning-highlight) !important}.sd-bg-danger{background-color:var(--sd-color-danger) !important}.sd-bg-text-danger{color:var(--sd-color-danger-text) !important}button.sd-bg-danger:focus,button.sd-bg-danger:hover{background-color:var(--sd-color-danger-highlight) !important}a.sd-bg-danger:focus,a.sd-bg-danger:hover{background-color:var(--sd-color-danger-highlight) !important}.sd-bg-light{background-color:var(--sd-color-light) !important}.sd-bg-text-light{color:var(--sd-color-light-text) !important}button.sd-bg-light:focus,button.sd-bg-light:hover{background-color:var(--sd-color-light-highlight) !important}a.sd-bg-light:focus,a.sd-bg-light:hover{background-color:var(--sd-color-light-highlight) !important}.sd-bg-muted{background-color:var(--sd-color-muted) !important}.sd-bg-text-muted{color:var(--sd-color-muted-text) !important}button.sd-bg-muted:focus,button.sd-bg-muted:hover{background-color:var(--sd-color-muted-highlight) !important}a.sd-bg-muted:focus,a.sd-bg-muted:hover{background-color:var(--sd-color-muted-highlight) !important}.sd-bg-dark{background-color:var(--sd-color-dark) !important}.sd-bg-text-dark{color:var(--sd-color-dark-text) !important}button.sd-bg-dark:focus,button.sd-bg-dark:hover{background-color:var(--sd-color-dark-highlight) !important}a.sd-bg-dark:focus,a.sd-bg-dark:hover{background-color:var(--sd-color-dark-highlight) !important}.sd-bg-black{background-color:var(--sd-color-black) !important}.sd-bg-text-black{color:var(--sd-color-black-text) !important}button.sd-bg-black:focus,button.sd-bg-black:hover{background-color:var(--sd-color-black-highlight) !important}a.sd-bg-black:focus,a.sd-bg-black:hover{background-color:var(--sd-color-black-highlight) !important}.sd-bg-white{background-color:var(--sd-color-white) !important}.sd-bg-text-white{color:var(--sd-color-white-text) !important}button.sd-bg-white:focus,button.sd-bg-white:hover{background-color:var(--sd-color-white-highlight) !important}a.sd-bg-white:focus,a.sd-bg-white:hover{background-color:var(--sd-color-white-highlight) !important}.sd-text-primary,.sd-text-primary>p{color:var(--sd-color-primary) !important}a.sd-text-primary:focus,a.sd-text-primary:hover{color:var(--sd-color-primary-highlight) !important}.sd-text-secondary,.sd-text-secondary>p{color:var(--sd-color-secondary) !important}a.sd-text-secondary:focus,a.sd-text-secondary:hover{color:var(--sd-color-secondary-highlight) !important}.sd-text-success,.sd-text-success>p{color:var(--sd-color-success) !important}a.sd-text-success:focus,a.sd-text-success:hover{color:var(--sd-color-success-highlight) !important}.sd-text-info,.sd-text-info>p{color:var(--sd-color-info) !important}a.sd-text-info:focus,a.sd-text-info:hover{color:var(--sd-color-info-highlight) !important}.sd-text-warning,.sd-text-warning>p{color:var(--sd-color-warning) !important}a.sd-text-warning:focus,a.sd-text-warning:hover{color:var(--sd-color-warning-highlight) !important}.sd-text-danger,.sd-text-danger>p{color:var(--sd-color-danger) !important}a.sd-text-danger:focus,a.sd-text-danger:hover{color:var(--sd-color-danger-highlight) !important}.sd-text-light,.sd-text-light>p{color:var(--sd-color-light) !important}a.sd-text-light:focus,a.sd-text-light:hover{color:var(--sd-color-light-highlight) !important}.sd-text-muted,.sd-text-muted>p{color:var(--sd-color-muted) !important}a.sd-text-muted:focus,a.sd-text-muted:hover{color:var(--sd-color-muted-highlight) !important}.sd-text-dark,.sd-text-dark>p{color:var(--sd-color-dark) !important}a.sd-text-dark:focus,a.sd-text-dark:hover{color:var(--sd-color-dark-highlight) !important}.sd-text-black,.sd-text-black>p{color:var(--sd-color-black) !important}a.sd-text-black:focus,a.sd-text-black:hover{color:var(--sd-color-black-highlight) !important}.sd-text-white,.sd-text-white>p{color:var(--sd-color-white) !important}a.sd-text-white:focus,a.sd-text-white:hover{color:var(--sd-color-white-highlight) !important}.sd-outline-primary{border-color:var(--sd-color-primary) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-primary:focus,a.sd-outline-primary:hover{border-color:var(--sd-color-primary-highlight) !important}.sd-outline-secondary{border-color:var(--sd-color-secondary) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-secondary:focus,a.sd-outline-secondary:hover{border-color:var(--sd-color-secondary-highlight) !important}.sd-outline-success{border-color:var(--sd-color-success) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-success:focus,a.sd-outline-success:hover{border-color:var(--sd-color-success-highlight) !important}.sd-outline-info{border-color:var(--sd-color-info) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-info:focus,a.sd-outline-info:hover{border-color:var(--sd-color-info-highlight) !important}.sd-outline-warning{border-color:var(--sd-color-warning) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-warning:focus,a.sd-outline-warning:hover{border-color:var(--sd-color-warning-highlight) !important}.sd-outline-danger{border-color:var(--sd-color-danger) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-danger:focus,a.sd-outline-danger:hover{border-color:var(--sd-color-danger-highlight) !important}.sd-outline-light{border-color:var(--sd-color-light) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-light:focus,a.sd-outline-light:hover{border-color:var(--sd-color-light-highlight) !important}.sd-outline-muted{border-color:var(--sd-color-muted) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-muted:focus,a.sd-outline-muted:hover{border-color:var(--sd-color-muted-highlight) !important}.sd-outline-dark{border-color:var(--sd-color-dark) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-dark:focus,a.sd-outline-dark:hover{border-color:var(--sd-color-dark-highlight) !important}.sd-outline-black{border-color:var(--sd-color-black) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-black:focus,a.sd-outline-black:hover{border-color:var(--sd-color-black-highlight) !important}.sd-outline-white{border-color:var(--sd-color-white) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-white:focus,a.sd-outline-white:hover{border-color:var(--sd-color-white-highlight) !important}.sd-bg-transparent{background-color:transparent !important}.sd-outline-transparent{border-color:transparent !important}.sd-text-transparent{color:transparent !important}.sd-p-0{padding:0 !important}.sd-pt-0,.sd-py-0{padding-top:0 !important}.sd-pr-0,.sd-px-0{padding-right:0 !important}.sd-pb-0,.sd-py-0{padding-bottom:0 !important}.sd-pl-0,.sd-px-0{padding-left:0 !important}.sd-p-1{padding:.25rem !important}.sd-pt-1,.sd-py-1{padding-top:.25rem !important}.sd-pr-1,.sd-px-1{padding-right:.25rem !important}.sd-pb-1,.sd-py-1{padding-bottom:.25rem !important}.sd-pl-1,.sd-px-1{padding-left:.25rem !important}.sd-p-2{padding:.5rem !important}.sd-pt-2,.sd-py-2{padding-top:.5rem !important}.sd-pr-2,.sd-px-2{padding-right:.5rem !important}.sd-pb-2,.sd-py-2{padding-bottom:.5rem !important}.sd-pl-2,.sd-px-2{padding-left:.5rem !important}.sd-p-3{padding:1rem !important}.sd-pt-3,.sd-py-3{padding-top:1rem !important}.sd-pr-3,.sd-px-3{padding-right:1rem !important}.sd-pb-3,.sd-py-3{padding-bottom:1rem !important}.sd-pl-3,.sd-px-3{padding-left:1rem !important}.sd-p-4{padding:1.5rem !important}.sd-pt-4,.sd-py-4{padding-top:1.5rem !important}.sd-pr-4,.sd-px-4{padding-right:1.5rem !important}.sd-pb-4,.sd-py-4{padding-bottom:1.5rem !important}.sd-pl-4,.sd-px-4{padding-left:1.5rem !important}.sd-p-5{padding:3rem !important}.sd-pt-5,.sd-py-5{padding-top:3rem !important}.sd-pr-5,.sd-px-5{padding-right:3rem !important}.sd-pb-5,.sd-py-5{padding-bottom:3rem !important}.sd-pl-5,.sd-px-5{padding-left:3rem !important}.sd-m-auto{margin:auto !important}.sd-mt-auto,.sd-my-auto{margin-top:auto !important}.sd-mr-auto,.sd-mx-auto{margin-right:auto !important}.sd-mb-auto,.sd-my-auto{margin-bottom:auto !important}.sd-ml-auto,.sd-mx-auto{margin-left:auto !important}.sd-m-0{margin:0 !important}.sd-mt-0,.sd-my-0{margin-top:0 !important}.sd-mr-0,.sd-mx-0{margin-right:0 !important}.sd-mb-0,.sd-my-0{margin-bottom:0 !important}.sd-ml-0,.sd-mx-0{margin-left:0 !important}.sd-m-1{margin:.25rem !important}.sd-mt-1,.sd-my-1{margin-top:.25rem !important}.sd-mr-1,.sd-mx-1{margin-right:.25rem !important}.sd-mb-1,.sd-my-1{margin-bottom:.25rem !important}.sd-ml-1,.sd-mx-1{margin-left:.25rem !important}.sd-m-2{margin:.5rem !important}.sd-mt-2,.sd-my-2{margin-top:.5rem !important}.sd-mr-2,.sd-mx-2{margin-right:.5rem !important}.sd-mb-2,.sd-my-2{margin-bottom:.5rem !important}.sd-ml-2,.sd-mx-2{margin-left:.5rem !important}.sd-m-3{margin:1rem !important}.sd-mt-3,.sd-my-3{margin-top:1rem !important}.sd-mr-3,.sd-mx-3{margin-right:1rem !important}.sd-mb-3,.sd-my-3{margin-bottom:1rem !important}.sd-ml-3,.sd-mx-3{margin-left:1rem !important}.sd-m-4{margin:1.5rem !important}.sd-mt-4,.sd-my-4{margin-top:1.5rem !important}.sd-mr-4,.sd-mx-4{margin-right:1.5rem !important}.sd-mb-4,.sd-my-4{margin-bottom:1.5rem !important}.sd-ml-4,.sd-mx-4{margin-left:1.5rem !important}.sd-m-5{margin:3rem !important}.sd-mt-5,.sd-my-5{margin-top:3rem !important}.sd-mr-5,.sd-mx-5{margin-right:3rem !important}.sd-mb-5,.sd-my-5{margin-bottom:3rem !important}.sd-ml-5,.sd-mx-5{margin-left:3rem !important}.sd-w-25{width:25% !important}.sd-w-50{width:50% !important}.sd-w-75{width:75% !important}.sd-w-100{width:100% !important}.sd-w-auto{width:auto !important}.sd-h-25{height:25% !important}.sd-h-50{height:50% !important}.sd-h-75{height:75% !important}.sd-h-100{height:100% !important}.sd-h-auto{height:auto !important}.sd-d-none{display:none !important}.sd-d-inline{display:inline !important}.sd-d-inline-block{display:inline-block !important}.sd-d-block{display:block !important}.sd-d-grid{display:grid !important}.sd-d-flex-row{display:-ms-flexbox !important;display:flex !important;flex-direction:row !important}.sd-d-flex-column{display:-ms-flexbox !important;display:flex !important;flex-direction:column !important}.sd-d-inline-flex{display:-ms-inline-flexbox !important;display:inline-flex !important}@media(min-width: 576px){.sd-d-sm-none{display:none !important}.sd-d-sm-inline{display:inline !important}.sd-d-sm-inline-block{display:inline-block !important}.sd-d-sm-block{display:block !important}.sd-d-sm-grid{display:grid !important}.sd-d-sm-flex{display:-ms-flexbox !important;display:flex !important}.sd-d-sm-inline-flex{display:-ms-inline-flexbox !important;display:inline-flex !important}}@media(min-width: 768px){.sd-d-md-none{display:none !important}.sd-d-md-inline{display:inline !important}.sd-d-md-inline-block{display:inline-block !important}.sd-d-md-block{display:block !important}.sd-d-md-grid{display:grid !important}.sd-d-md-flex{display:-ms-flexbox !important;display:flex !important}.sd-d-md-inline-flex{display:-ms-inline-flexbox !important;display:inline-flex !important}}@media(min-width: 992px){.sd-d-lg-none{display:none !important}.sd-d-lg-inline{display:inline !important}.sd-d-lg-inline-block{display:inline-block !important}.sd-d-lg-block{display:block !important}.sd-d-lg-grid{display:grid !important}.sd-d-lg-flex{display:-ms-flexbox !important;display:flex !important}.sd-d-lg-inline-flex{display:-ms-inline-flexbox !important;display:inline-flex !important}}@media(min-width: 1200px){.sd-d-xl-none{display:none !important}.sd-d-xl-inline{display:inline !important}.sd-d-xl-inline-block{display:inline-block !important}.sd-d-xl-block{display:block !important}.sd-d-xl-grid{display:grid !important}.sd-d-xl-flex{display:-ms-flexbox !important;display:flex !important}.sd-d-xl-inline-flex{display:-ms-inline-flexbox !important;display:inline-flex !important}}.sd-align-major-start{justify-content:flex-start !important}.sd-align-major-end{justify-content:flex-end !important}.sd-align-major-center{justify-content:center !important}.sd-align-major-justify{justify-content:space-between !important}.sd-align-major-spaced{justify-content:space-evenly !important}.sd-align-minor-start{align-items:flex-start !important}.sd-align-minor-end{align-items:flex-end !important}.sd-align-minor-center{align-items:center !important}.sd-align-minor-stretch{align-items:stretch !important}.sd-text-justify{text-align:justify !important}.sd-text-left{text-align:left !important}.sd-text-right{text-align:right !important}.sd-text-center{text-align:center !important}.sd-font-weight-light{font-weight:300 !important}.sd-font-weight-lighter{font-weight:lighter !important}.sd-font-weight-normal{font-weight:400 !important}.sd-font-weight-bold{font-weight:700 !important}.sd-font-weight-bolder{font-weight:bolder !important}.sd-font-italic{font-style:italic !important}.sd-text-decoration-none{text-decoration:none !important}.sd-text-lowercase{text-transform:lowercase !important}.sd-text-uppercase{text-transform:uppercase !important}.sd-text-capitalize{text-transform:capitalize !important}.sd-text-wrap{white-space:normal !important}.sd-text-nowrap{white-space:nowrap !important}.sd-text-truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.sd-fs-1,.sd-fs-1>p{font-size:calc(1.375rem + 1.5vw) !important;line-height:unset !important}.sd-fs-2,.sd-fs-2>p{font-size:calc(1.325rem + 0.9vw) !important;line-height:unset !important}.sd-fs-3,.sd-fs-3>p{font-size:calc(1.3rem + 0.6vw) !important;line-height:unset !important}.sd-fs-4,.sd-fs-4>p{font-size:calc(1.275rem + 0.3vw) !important;line-height:unset !important}.sd-fs-5,.sd-fs-5>p{font-size:1.25rem !important;line-height:unset !important}.sd-fs-6,.sd-fs-6>p{font-size:1rem !important;line-height:unset !important}.sd-border-0{border:0 solid !important}.sd-border-top-0{border-top:0 solid !important}.sd-border-bottom-0{border-bottom:0 solid !important}.sd-border-right-0{border-right:0 solid !important}.sd-border-left-0{border-left:0 solid !important}.sd-border-1{border:1px solid !important}.sd-border-top-1{border-top:1px solid !important}.sd-border-bottom-1{border-bottom:1px solid !important}.sd-border-right-1{border-right:1px solid !important}.sd-border-left-1{border-left:1px solid !important}.sd-border-2{border:2px solid !important}.sd-border-top-2{border-top:2px solid !important}.sd-border-bottom-2{border-bottom:2px solid !important}.sd-border-right-2{border-right:2px solid !important}.sd-border-left-2{border-left:2px solid !important}.sd-border-3{border:3px solid !important}.sd-border-top-3{border-top:3px solid !important}.sd-border-bottom-3{border-bottom:3px solid !important}.sd-border-right-3{border-right:3px solid !important}.sd-border-left-3{border-left:3px solid !important}.sd-border-4{border:4px solid !important}.sd-border-top-4{border-top:4px solid !important}.sd-border-bottom-4{border-bottom:4px solid !important}.sd-border-right-4{border-right:4px solid !important}.sd-border-left-4{border-left:4px solid !important}.sd-border-5{border:5px solid !important}.sd-border-top-5{border-top:5px solid !important}.sd-border-bottom-5{border-bottom:5px solid !important}.sd-border-right-5{border-right:5px solid !important}.sd-border-left-5{border-left:5px solid !important}.sd-rounded-0{border-radius:0 !important}.sd-rounded-1{border-radius:.2rem !important}.sd-rounded-2{border-radius:.3rem !important}.sd-rounded-3{border-radius:.5rem !important}.sd-rounded-pill{border-radius:50rem !important}.sd-rounded-circle{border-radius:50% !important}.shadow-none{box-shadow:none !important}.sd-shadow-sm{box-shadow:0 .125rem .25rem var(--sd-color-shadow) !important}.sd-shadow-md{box-shadow:0 .5rem 1rem var(--sd-color-shadow) !important}.sd-shadow-lg{box-shadow:0 1rem 3rem var(--sd-color-shadow) !important}@keyframes sd-slide-from-left{0%{transform:translateX(-100%)}100%{transform:translateX(0)}}@keyframes sd-slide-from-right{0%{transform:translateX(200%)}100%{transform:translateX(0)}}@keyframes sd-grow100{0%{transform:scale(0);opacity:.5}100%{transform:scale(1);opacity:1}}@keyframes sd-grow50{0%{transform:scale(0.5);opacity:.5}100%{transform:scale(1);opacity:1}}@keyframes sd-grow50-rot20{0%{transform:scale(0.5) rotateZ(-20deg);opacity:.5}75%{transform:scale(1) rotateZ(5deg);opacity:1}95%{transform:scale(1) rotateZ(-1deg);opacity:1}100%{transform:scale(1) rotateZ(0);opacity:1}}.sd-animate-slide-from-left{animation:1s ease-out 0s 1 normal none running sd-slide-from-left}.sd-animate-slide-from-right{animation:1s ease-out 0s 1 normal none running sd-slide-from-right}.sd-animate-grow100{animation:1s ease-out 0s 1 normal none running sd-grow100}.sd-animate-grow50{animation:1s ease-out 0s 1 normal none running sd-grow50}.sd-animate-grow50-rot20{animation:1s ease-out 0s 1 normal none running sd-grow50-rot20}.sd-badge{display:inline-block;padding:.35em .65em;font-size:.75em;font-weight:700;line-height:1;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25rem}.sd-badge:empty{display:none}a.sd-badge{text-decoration:none}.sd-btn .sd-badge{position:relative;top:-1px}.sd-btn{background-color:transparent;border:1px solid transparent;border-radius:.25rem;cursor:pointer;display:inline-block;font-weight:400;font-size:1rem;line-height:1.5;padding:.375rem .75rem;text-align:center;text-decoration:none;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;vertical-align:middle;user-select:none;-moz-user-select:none;-ms-user-select:none;-webkit-user-select:none}.sd-btn:hover{text-decoration:none}@media(prefers-reduced-motion: reduce){.sd-btn{transition:none}}.sd-btn-primary,.sd-btn-outline-primary:hover,.sd-btn-outline-primary:focus{color:var(--sd-color-primary-text) !important;background-color:var(--sd-color-primary) !important;border-color:var(--sd-color-primary) !important;border-width:1px !important;border-style:solid !important}.sd-btn-primary:hover,.sd-btn-primary:focus{color:var(--sd-color-primary-text) !important;background-color:var(--sd-color-primary-highlight) !important;border-color:var(--sd-color-primary-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-primary{color:var(--sd-color-primary) !important;border-color:var(--sd-color-primary) !important;border-width:1px !important;border-style:solid !important}.sd-btn-secondary,.sd-btn-outline-secondary:hover,.sd-btn-outline-secondary:focus{color:var(--sd-color-secondary-text) !important;background-color:var(--sd-color-secondary) !important;border-color:var(--sd-color-secondary) !important;border-width:1px !important;border-style:solid !important}.sd-btn-secondary:hover,.sd-btn-secondary:focus{color:var(--sd-color-secondary-text) !important;background-color:var(--sd-color-secondary-highlight) !important;border-color:var(--sd-color-secondary-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-secondary{color:var(--sd-color-secondary) !important;border-color:var(--sd-color-secondary) !important;border-width:1px !important;border-style:solid !important}.sd-btn-success,.sd-btn-outline-success:hover,.sd-btn-outline-success:focus{color:var(--sd-color-success-text) !important;background-color:var(--sd-color-success) !important;border-color:var(--sd-color-success) !important;border-width:1px !important;border-style:solid !important}.sd-btn-success:hover,.sd-btn-success:focus{color:var(--sd-color-success-text) !important;background-color:var(--sd-color-success-highlight) !important;border-color:var(--sd-color-success-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-success{color:var(--sd-color-success) !important;border-color:var(--sd-color-success) !important;border-width:1px !important;border-style:solid !important}.sd-btn-info,.sd-btn-outline-info:hover,.sd-btn-outline-info:focus{color:var(--sd-color-info-text) !important;background-color:var(--sd-color-info) !important;border-color:var(--sd-color-info) !important;border-width:1px !important;border-style:solid !important}.sd-btn-info:hover,.sd-btn-info:focus{color:var(--sd-color-info-text) !important;background-color:var(--sd-color-info-highlight) !important;border-color:var(--sd-color-info-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-info{color:var(--sd-color-info) !important;border-color:var(--sd-color-info) !important;border-width:1px !important;border-style:solid !important}.sd-btn-warning,.sd-btn-outline-warning:hover,.sd-btn-outline-warning:focus{color:var(--sd-color-warning-text) !important;background-color:var(--sd-color-warning) !important;border-color:var(--sd-color-warning) !important;border-width:1px !important;border-style:solid !important}.sd-btn-warning:hover,.sd-btn-warning:focus{color:var(--sd-color-warning-text) !important;background-color:var(--sd-color-warning-highlight) !important;border-color:var(--sd-color-warning-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-warning{color:var(--sd-color-warning) !important;border-color:var(--sd-color-warning) !important;border-width:1px !important;border-style:solid !important}.sd-btn-danger,.sd-btn-outline-danger:hover,.sd-btn-outline-danger:focus{color:var(--sd-color-danger-text) !important;background-color:var(--sd-color-danger) !important;border-color:var(--sd-color-danger) !important;border-width:1px !important;border-style:solid !important}.sd-btn-danger:hover,.sd-btn-danger:focus{color:var(--sd-color-danger-text) !important;background-color:var(--sd-color-danger-highlight) !important;border-color:var(--sd-color-danger-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-danger{color:var(--sd-color-danger) !important;border-color:var(--sd-color-danger) !important;border-width:1px !important;border-style:solid !important}.sd-btn-light,.sd-btn-outline-light:hover,.sd-btn-outline-light:focus{color:var(--sd-color-light-text) !important;background-color:var(--sd-color-light) !important;border-color:var(--sd-color-light) !important;border-width:1px !important;border-style:solid !important}.sd-btn-light:hover,.sd-btn-light:focus{color:var(--sd-color-light-text) !important;background-color:var(--sd-color-light-highlight) !important;border-color:var(--sd-color-light-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-light{color:var(--sd-color-light) !important;border-color:var(--sd-color-light) !important;border-width:1px !important;border-style:solid !important}.sd-btn-muted,.sd-btn-outline-muted:hover,.sd-btn-outline-muted:focus{color:var(--sd-color-muted-text) !important;background-color:var(--sd-color-muted) !important;border-color:var(--sd-color-muted) !important;border-width:1px !important;border-style:solid !important}.sd-btn-muted:hover,.sd-btn-muted:focus{color:var(--sd-color-muted-text) !important;background-color:var(--sd-color-muted-highlight) !important;border-color:var(--sd-color-muted-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-muted{color:var(--sd-color-muted) !important;border-color:var(--sd-color-muted) !important;border-width:1px !important;border-style:solid !important}.sd-btn-dark,.sd-btn-outline-dark:hover,.sd-btn-outline-dark:focus{color:var(--sd-color-dark-text) !important;background-color:var(--sd-color-dark) !important;border-color:var(--sd-color-dark) !important;border-width:1px !important;border-style:solid !important}.sd-btn-dark:hover,.sd-btn-dark:focus{color:var(--sd-color-dark-text) !important;background-color:var(--sd-color-dark-highlight) !important;border-color:var(--sd-color-dark-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-dark{color:var(--sd-color-dark) !important;border-color:var(--sd-color-dark) !important;border-width:1px !important;border-style:solid !important}.sd-btn-black,.sd-btn-outline-black:hover,.sd-btn-outline-black:focus{color:var(--sd-color-black-text) !important;background-color:var(--sd-color-black) !important;border-color:var(--sd-color-black) !important;border-width:1px !important;border-style:solid !important}.sd-btn-black:hover,.sd-btn-black:focus{color:var(--sd-color-black-text) !important;background-color:var(--sd-color-black-highlight) !important;border-color:var(--sd-color-black-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-black{color:var(--sd-color-black) !important;border-color:var(--sd-color-black) !important;border-width:1px !important;border-style:solid !important}.sd-btn-white,.sd-btn-outline-white:hover,.sd-btn-outline-white:focus{color:var(--sd-color-white-text) !important;background-color:var(--sd-color-white) !important;border-color:var(--sd-color-white) !important;border-width:1px !important;border-style:solid !important}.sd-btn-white:hover,.sd-btn-white:focus{color:var(--sd-color-white-text) !important;background-color:var(--sd-color-white-highlight) !important;border-color:var(--sd-color-white-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-white{color:var(--sd-color-white) !important;border-color:var(--sd-color-white) !important;border-width:1px !important;border-style:solid !important}.sd-stretched-link::after{position:absolute;top:0;right:0;bottom:0;left:0;z-index:1;content:""}.sd-hide-link-text{font-size:0}.sd-octicon,.sd-material-icon{display:inline-block;fill:currentColor;vertical-align:middle}.sd-avatar-xs{border-radius:50%;object-fit:cover;object-position:center;width:1rem;height:1rem}.sd-avatar-sm{border-radius:50%;object-fit:cover;object-position:center;width:3rem;height:3rem}.sd-avatar-md{border-radius:50%;object-fit:cover;object-position:center;width:5rem;height:5rem}.sd-avatar-lg{border-radius:50%;object-fit:cover;object-position:center;width:7rem;height:7rem}.sd-avatar-xl{border-radius:50%;object-fit:cover;object-position:center;width:10rem;height:10rem}.sd-avatar-inherit{border-radius:50%;object-fit:cover;object-position:center;width:inherit;height:inherit}.sd-avatar-initial{border-radius:50%;object-fit:cover;object-position:center;width:initial;height:initial}.sd-card{background-clip:border-box;background-color:var(--sd-color-card-background);border:1px solid var(--sd-color-card-border);border-radius:.25rem;color:var(--sd-color-card-text);display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;min-width:0;position:relative;word-wrap:break-word}.sd-card>hr{margin-left:0;margin-right:0}.sd-card-hover:hover{border-color:var(--sd-color-card-border-hover);transform:scale(1.01)}.sd-card-body{-ms-flex:1 1 auto;flex:1 1 auto;padding:1rem 1rem}.sd-card-title{margin-bottom:.5rem}.sd-card-subtitle{margin-top:-0.25rem;margin-bottom:0}.sd-card-text:last-child{margin-bottom:0}.sd-card-link:hover{text-decoration:none}.sd-card-link+.card-link{margin-left:1rem}.sd-card-header{padding:.5rem 1rem;margin-bottom:0;background-color:var(--sd-color-card-header);border-bottom:1px solid var(--sd-color-card-border)}.sd-card-header:first-child{border-radius:calc(0.25rem - 1px) calc(0.25rem - 1px) 0 0}.sd-card-footer{padding:.5rem 1rem;background-color:var(--sd-color-card-footer);border-top:1px solid var(--sd-color-card-border)}.sd-card-footer:last-child{border-radius:0 0 calc(0.25rem - 1px) calc(0.25rem - 1px)}.sd-card-header-tabs{margin-right:-0.5rem;margin-bottom:-0.5rem;margin-left:-0.5rem;border-bottom:0}.sd-card-header-pills{margin-right:-0.5rem;margin-left:-0.5rem}.sd-card-img-overlay{position:absolute;top:0;right:0;bottom:0;left:0;padding:1rem;border-radius:calc(0.25rem - 1px)}.sd-card-img,.sd-card-img-bottom,.sd-card-img-top{width:100%}.sd-card-img,.sd-card-img-top{border-top-left-radius:calc(0.25rem - 1px);border-top-right-radius:calc(0.25rem - 1px)}.sd-card-img,.sd-card-img-bottom{border-bottom-left-radius:calc(0.25rem - 1px);border-bottom-right-radius:calc(0.25rem - 1px)}.sd-cards-carousel{width:100%;display:flex;flex-wrap:nowrap;-ms-flex-direction:row;flex-direction:row;overflow-x:hidden;scroll-snap-type:x mandatory}.sd-cards-carousel.sd-show-scrollbar{overflow-x:auto}.sd-cards-carousel:hover,.sd-cards-carousel:focus{overflow-x:auto}.sd-cards-carousel>.sd-card{flex-shrink:0;scroll-snap-align:start}.sd-cards-carousel>.sd-card:not(:last-child){margin-right:3px}.sd-card-cols-1>.sd-card{width:90%}.sd-card-cols-2>.sd-card{width:45%}.sd-card-cols-3>.sd-card{width:30%}.sd-card-cols-4>.sd-card{width:22.5%}.sd-card-cols-5>.sd-card{width:18%}.sd-card-cols-6>.sd-card{width:15%}.sd-card-cols-7>.sd-card{width:12.8571428571%}.sd-card-cols-8>.sd-card{width:11.25%}.sd-card-cols-9>.sd-card{width:10%}.sd-card-cols-10>.sd-card{width:9%}.sd-card-cols-11>.sd-card{width:8.1818181818%}.sd-card-cols-12>.sd-card{width:7.5%}.sd-container,.sd-container-fluid,.sd-container-lg,.sd-container-md,.sd-container-sm,.sd-container-xl{margin-left:auto;margin-right:auto;padding-left:var(--sd-gutter-x, 0.75rem);padding-right:var(--sd-gutter-x, 0.75rem);width:100%}@media(min-width: 576px){.sd-container-sm,.sd-container{max-width:540px}}@media(min-width: 768px){.sd-container-md,.sd-container-sm,.sd-container{max-width:720px}}@media(min-width: 992px){.sd-container-lg,.sd-container-md,.sd-container-sm,.sd-container{max-width:960px}}@media(min-width: 1200px){.sd-container-xl,.sd-container-lg,.sd-container-md,.sd-container-sm,.sd-container{max-width:1140px}}.sd-row{--sd-gutter-x: 1.5rem;--sd-gutter-y: 0;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;margin-top:calc(var(--sd-gutter-y) * -1);margin-right:calc(var(--sd-gutter-x) * -0.5);margin-left:calc(var(--sd-gutter-x) * -0.5)}.sd-row>*{box-sizing:border-box;flex-shrink:0;width:100%;max-width:100%;padding-right:calc(var(--sd-gutter-x) * 0.5);padding-left:calc(var(--sd-gutter-x) * 0.5);margin-top:var(--sd-gutter-y)}.sd-col{flex:1 0 0%;-ms-flex:1 0 0%}.sd-row-cols-auto>*{flex:0 0 auto;width:auto}.sd-row-cols-1>*{flex:0 0 auto;-ms-flex:0 0 auto;width:100%}.sd-row-cols-2>*{flex:0 0 auto;-ms-flex:0 0 auto;width:50%}.sd-row-cols-3>*{flex:0 0 auto;-ms-flex:0 0 auto;width:33.3333333333%}.sd-row-cols-4>*{flex:0 0 auto;-ms-flex:0 0 auto;width:25%}.sd-row-cols-5>*{flex:0 0 auto;-ms-flex:0 0 auto;width:20%}.sd-row-cols-6>*{flex:0 0 auto;-ms-flex:0 0 auto;width:16.6666666667%}.sd-row-cols-7>*{flex:0 0 auto;-ms-flex:0 0 auto;width:14.2857142857%}.sd-row-cols-8>*{flex:0 0 auto;-ms-flex:0 0 auto;width:12.5%}.sd-row-cols-9>*{flex:0 0 auto;-ms-flex:0 0 auto;width:11.1111111111%}.sd-row-cols-10>*{flex:0 0 auto;-ms-flex:0 0 auto;width:10%}.sd-row-cols-11>*{flex:0 0 auto;-ms-flex:0 0 auto;width:9.0909090909%}.sd-row-cols-12>*{flex:0 0 auto;-ms-flex:0 0 auto;width:8.3333333333%}@media(min-width: 576px){.sd-col-sm{flex:1 0 0%;-ms-flex:1 0 0%}.sd-row-cols-sm-auto{flex:1 0 auto;-ms-flex:1 0 auto;width:100%}.sd-row-cols-sm-1>*{flex:0 0 auto;-ms-flex:0 0 auto;width:100%}.sd-row-cols-sm-2>*{flex:0 0 auto;-ms-flex:0 0 auto;width:50%}.sd-row-cols-sm-3>*{flex:0 0 auto;-ms-flex:0 0 auto;width:33.3333333333%}.sd-row-cols-sm-4>*{flex:0 0 auto;-ms-flex:0 0 auto;width:25%}.sd-row-cols-sm-5>*{flex:0 0 auto;-ms-flex:0 0 auto;width:20%}.sd-row-cols-sm-6>*{flex:0 0 auto;-ms-flex:0 0 auto;width:16.6666666667%}.sd-row-cols-sm-7>*{flex:0 0 auto;-ms-flex:0 0 auto;width:14.2857142857%}.sd-row-cols-sm-8>*{flex:0 0 auto;-ms-flex:0 0 auto;width:12.5%}.sd-row-cols-sm-9>*{flex:0 0 auto;-ms-flex:0 0 auto;width:11.1111111111%}.sd-row-cols-sm-10>*{flex:0 0 auto;-ms-flex:0 0 auto;width:10%}.sd-row-cols-sm-11>*{flex:0 0 auto;-ms-flex:0 0 auto;width:9.0909090909%}.sd-row-cols-sm-12>*{flex:0 0 auto;-ms-flex:0 0 auto;width:8.3333333333%}}@media(min-width: 768px){.sd-col-md{flex:1 0 0%;-ms-flex:1 0 0%}.sd-row-cols-md-auto{flex:1 0 auto;-ms-flex:1 0 auto;width:100%}.sd-row-cols-md-1>*{flex:0 0 auto;-ms-flex:0 0 auto;width:100%}.sd-row-cols-md-2>*{flex:0 0 auto;-ms-flex:0 0 auto;width:50%}.sd-row-cols-md-3>*{flex:0 0 auto;-ms-flex:0 0 auto;width:33.3333333333%}.sd-row-cols-md-4>*{flex:0 0 auto;-ms-flex:0 0 auto;width:25%}.sd-row-cols-md-5>*{flex:0 0 auto;-ms-flex:0 0 auto;width:20%}.sd-row-cols-md-6>*{flex:0 0 auto;-ms-flex:0 0 auto;width:16.6666666667%}.sd-row-cols-md-7>*{flex:0 0 auto;-ms-flex:0 0 auto;width:14.2857142857%}.sd-row-cols-md-8>*{flex:0 0 auto;-ms-flex:0 0 auto;width:12.5%}.sd-row-cols-md-9>*{flex:0 0 auto;-ms-flex:0 0 auto;width:11.1111111111%}.sd-row-cols-md-10>*{flex:0 0 auto;-ms-flex:0 0 auto;width:10%}.sd-row-cols-md-11>*{flex:0 0 auto;-ms-flex:0 0 auto;width:9.0909090909%}.sd-row-cols-md-12>*{flex:0 0 auto;-ms-flex:0 0 auto;width:8.3333333333%}}@media(min-width: 992px){.sd-col-lg{flex:1 0 0%;-ms-flex:1 0 0%}.sd-row-cols-lg-auto{flex:1 0 auto;-ms-flex:1 0 auto;width:100%}.sd-row-cols-lg-1>*{flex:0 0 auto;-ms-flex:0 0 auto;width:100%}.sd-row-cols-lg-2>*{flex:0 0 auto;-ms-flex:0 0 auto;width:50%}.sd-row-cols-lg-3>*{flex:0 0 auto;-ms-flex:0 0 auto;width:33.3333333333%}.sd-row-cols-lg-4>*{flex:0 0 auto;-ms-flex:0 0 auto;width:25%}.sd-row-cols-lg-5>*{flex:0 0 auto;-ms-flex:0 0 auto;width:20%}.sd-row-cols-lg-6>*{flex:0 0 auto;-ms-flex:0 0 auto;width:16.6666666667%}.sd-row-cols-lg-7>*{flex:0 0 auto;-ms-flex:0 0 auto;width:14.2857142857%}.sd-row-cols-lg-8>*{flex:0 0 auto;-ms-flex:0 0 auto;width:12.5%}.sd-row-cols-lg-9>*{flex:0 0 auto;-ms-flex:0 0 auto;width:11.1111111111%}.sd-row-cols-lg-10>*{flex:0 0 auto;-ms-flex:0 0 auto;width:10%}.sd-row-cols-lg-11>*{flex:0 0 auto;-ms-flex:0 0 auto;width:9.0909090909%}.sd-row-cols-lg-12>*{flex:0 0 auto;-ms-flex:0 0 auto;width:8.3333333333%}}@media(min-width: 1200px){.sd-col-xl{flex:1 0 0%;-ms-flex:1 0 0%}.sd-row-cols-xl-auto{flex:1 0 auto;-ms-flex:1 0 auto;width:100%}.sd-row-cols-xl-1>*{flex:0 0 auto;-ms-flex:0 0 auto;width:100%}.sd-row-cols-xl-2>*{flex:0 0 auto;-ms-flex:0 0 auto;width:50%}.sd-row-cols-xl-3>*{flex:0 0 auto;-ms-flex:0 0 auto;width:33.3333333333%}.sd-row-cols-xl-4>*{flex:0 0 auto;-ms-flex:0 0 auto;width:25%}.sd-row-cols-xl-5>*{flex:0 0 auto;-ms-flex:0 0 auto;width:20%}.sd-row-cols-xl-6>*{flex:0 0 auto;-ms-flex:0 0 auto;width:16.6666666667%}.sd-row-cols-xl-7>*{flex:0 0 auto;-ms-flex:0 0 auto;width:14.2857142857%}.sd-row-cols-xl-8>*{flex:0 0 auto;-ms-flex:0 0 auto;width:12.5%}.sd-row-cols-xl-9>*{flex:0 0 auto;-ms-flex:0 0 auto;width:11.1111111111%}.sd-row-cols-xl-10>*{flex:0 0 auto;-ms-flex:0 0 auto;width:10%}.sd-row-cols-xl-11>*{flex:0 0 auto;-ms-flex:0 0 auto;width:9.0909090909%}.sd-row-cols-xl-12>*{flex:0 0 auto;-ms-flex:0 0 auto;width:8.3333333333%}}.sd-col-auto{flex:0 0 auto;-ms-flex:0 0 auto;width:auto}.sd-col-1{flex:0 0 auto;-ms-flex:0 0 auto;width:8.3333333333%}.sd-col-2{flex:0 0 auto;-ms-flex:0 0 auto;width:16.6666666667%}.sd-col-3{flex:0 0 auto;-ms-flex:0 0 auto;width:25%}.sd-col-4{flex:0 0 auto;-ms-flex:0 0 auto;width:33.3333333333%}.sd-col-5{flex:0 0 auto;-ms-flex:0 0 auto;width:41.6666666667%}.sd-col-6{flex:0 0 auto;-ms-flex:0 0 auto;width:50%}.sd-col-7{flex:0 0 auto;-ms-flex:0 0 auto;width:58.3333333333%}.sd-col-8{flex:0 0 auto;-ms-flex:0 0 auto;width:66.6666666667%}.sd-col-9{flex:0 0 auto;-ms-flex:0 0 auto;width:75%}.sd-col-10{flex:0 0 auto;-ms-flex:0 0 auto;width:83.3333333333%}.sd-col-11{flex:0 0 auto;-ms-flex:0 0 auto;width:91.6666666667%}.sd-col-12{flex:0 0 auto;-ms-flex:0 0 auto;width:100%}.sd-g-0,.sd-gy-0{--sd-gutter-y: 0}.sd-g-0,.sd-gx-0{--sd-gutter-x: 0}.sd-g-1,.sd-gy-1{--sd-gutter-y: 0.25rem}.sd-g-1,.sd-gx-1{--sd-gutter-x: 0.25rem}.sd-g-2,.sd-gy-2{--sd-gutter-y: 0.5rem}.sd-g-2,.sd-gx-2{--sd-gutter-x: 0.5rem}.sd-g-3,.sd-gy-3{--sd-gutter-y: 1rem}.sd-g-3,.sd-gx-3{--sd-gutter-x: 1rem}.sd-g-4,.sd-gy-4{--sd-gutter-y: 1.5rem}.sd-g-4,.sd-gx-4{--sd-gutter-x: 1.5rem}.sd-g-5,.sd-gy-5{--sd-gutter-y: 3rem}.sd-g-5,.sd-gx-5{--sd-gutter-x: 3rem}@media(min-width: 576px){.sd-col-sm-auto{-ms-flex:0 0 auto;flex:0 0 auto;width:auto}.sd-col-sm-1{-ms-flex:0 0 auto;flex:0 0 auto;width:8.3333333333%}.sd-col-sm-2{-ms-flex:0 0 auto;flex:0 0 auto;width:16.6666666667%}.sd-col-sm-3{-ms-flex:0 0 auto;flex:0 0 auto;width:25%}.sd-col-sm-4{-ms-flex:0 0 auto;flex:0 0 auto;width:33.3333333333%}.sd-col-sm-5{-ms-flex:0 0 auto;flex:0 0 auto;width:41.6666666667%}.sd-col-sm-6{-ms-flex:0 0 auto;flex:0 0 auto;width:50%}.sd-col-sm-7{-ms-flex:0 0 auto;flex:0 0 auto;width:58.3333333333%}.sd-col-sm-8{-ms-flex:0 0 auto;flex:0 0 auto;width:66.6666666667%}.sd-col-sm-9{-ms-flex:0 0 auto;flex:0 0 auto;width:75%}.sd-col-sm-10{-ms-flex:0 0 auto;flex:0 0 auto;width:83.3333333333%}.sd-col-sm-11{-ms-flex:0 0 auto;flex:0 0 auto;width:91.6666666667%}.sd-col-sm-12{-ms-flex:0 0 auto;flex:0 0 auto;width:100%}.sd-g-sm-0,.sd-gy-sm-0{--sd-gutter-y: 0}.sd-g-sm-0,.sd-gx-sm-0{--sd-gutter-x: 0}.sd-g-sm-1,.sd-gy-sm-1{--sd-gutter-y: 0.25rem}.sd-g-sm-1,.sd-gx-sm-1{--sd-gutter-x: 0.25rem}.sd-g-sm-2,.sd-gy-sm-2{--sd-gutter-y: 0.5rem}.sd-g-sm-2,.sd-gx-sm-2{--sd-gutter-x: 0.5rem}.sd-g-sm-3,.sd-gy-sm-3{--sd-gutter-y: 1rem}.sd-g-sm-3,.sd-gx-sm-3{--sd-gutter-x: 1rem}.sd-g-sm-4,.sd-gy-sm-4{--sd-gutter-y: 1.5rem}.sd-g-sm-4,.sd-gx-sm-4{--sd-gutter-x: 1.5rem}.sd-g-sm-5,.sd-gy-sm-5{--sd-gutter-y: 3rem}.sd-g-sm-5,.sd-gx-sm-5{--sd-gutter-x: 3rem}}@media(min-width: 768px){.sd-col-md-auto{-ms-flex:0 0 auto;flex:0 0 auto;width:auto}.sd-col-md-1{-ms-flex:0 0 auto;flex:0 0 auto;width:8.3333333333%}.sd-col-md-2{-ms-flex:0 0 auto;flex:0 0 auto;width:16.6666666667%}.sd-col-md-3{-ms-flex:0 0 auto;flex:0 0 auto;width:25%}.sd-col-md-4{-ms-flex:0 0 auto;flex:0 0 auto;width:33.3333333333%}.sd-col-md-5{-ms-flex:0 0 auto;flex:0 0 auto;width:41.6666666667%}.sd-col-md-6{-ms-flex:0 0 auto;flex:0 0 auto;width:50%}.sd-col-md-7{-ms-flex:0 0 auto;flex:0 0 auto;width:58.3333333333%}.sd-col-md-8{-ms-flex:0 0 auto;flex:0 0 auto;width:66.6666666667%}.sd-col-md-9{-ms-flex:0 0 auto;flex:0 0 auto;width:75%}.sd-col-md-10{-ms-flex:0 0 auto;flex:0 0 auto;width:83.3333333333%}.sd-col-md-11{-ms-flex:0 0 auto;flex:0 0 auto;width:91.6666666667%}.sd-col-md-12{-ms-flex:0 0 auto;flex:0 0 auto;width:100%}.sd-g-md-0,.sd-gy-md-0{--sd-gutter-y: 0}.sd-g-md-0,.sd-gx-md-0{--sd-gutter-x: 0}.sd-g-md-1,.sd-gy-md-1{--sd-gutter-y: 0.25rem}.sd-g-md-1,.sd-gx-md-1{--sd-gutter-x: 0.25rem}.sd-g-md-2,.sd-gy-md-2{--sd-gutter-y: 0.5rem}.sd-g-md-2,.sd-gx-md-2{--sd-gutter-x: 0.5rem}.sd-g-md-3,.sd-gy-md-3{--sd-gutter-y: 1rem}.sd-g-md-3,.sd-gx-md-3{--sd-gutter-x: 1rem}.sd-g-md-4,.sd-gy-md-4{--sd-gutter-y: 1.5rem}.sd-g-md-4,.sd-gx-md-4{--sd-gutter-x: 1.5rem}.sd-g-md-5,.sd-gy-md-5{--sd-gutter-y: 3rem}.sd-g-md-5,.sd-gx-md-5{--sd-gutter-x: 3rem}}@media(min-width: 992px){.sd-col-lg-auto{-ms-flex:0 0 auto;flex:0 0 auto;width:auto}.sd-col-lg-1{-ms-flex:0 0 auto;flex:0 0 auto;width:8.3333333333%}.sd-col-lg-2{-ms-flex:0 0 auto;flex:0 0 auto;width:16.6666666667%}.sd-col-lg-3{-ms-flex:0 0 auto;flex:0 0 auto;width:25%}.sd-col-lg-4{-ms-flex:0 0 auto;flex:0 0 auto;width:33.3333333333%}.sd-col-lg-5{-ms-flex:0 0 auto;flex:0 0 auto;width:41.6666666667%}.sd-col-lg-6{-ms-flex:0 0 auto;flex:0 0 auto;width:50%}.sd-col-lg-7{-ms-flex:0 0 auto;flex:0 0 auto;width:58.3333333333%}.sd-col-lg-8{-ms-flex:0 0 auto;flex:0 0 auto;width:66.6666666667%}.sd-col-lg-9{-ms-flex:0 0 auto;flex:0 0 auto;width:75%}.sd-col-lg-10{-ms-flex:0 0 auto;flex:0 0 auto;width:83.3333333333%}.sd-col-lg-11{-ms-flex:0 0 auto;flex:0 0 auto;width:91.6666666667%}.sd-col-lg-12{-ms-flex:0 0 auto;flex:0 0 auto;width:100%}.sd-g-lg-0,.sd-gy-lg-0{--sd-gutter-y: 0}.sd-g-lg-0,.sd-gx-lg-0{--sd-gutter-x: 0}.sd-g-lg-1,.sd-gy-lg-1{--sd-gutter-y: 0.25rem}.sd-g-lg-1,.sd-gx-lg-1{--sd-gutter-x: 0.25rem}.sd-g-lg-2,.sd-gy-lg-2{--sd-gutter-y: 0.5rem}.sd-g-lg-2,.sd-gx-lg-2{--sd-gutter-x: 0.5rem}.sd-g-lg-3,.sd-gy-lg-3{--sd-gutter-y: 1rem}.sd-g-lg-3,.sd-gx-lg-3{--sd-gutter-x: 1rem}.sd-g-lg-4,.sd-gy-lg-4{--sd-gutter-y: 1.5rem}.sd-g-lg-4,.sd-gx-lg-4{--sd-gutter-x: 1.5rem}.sd-g-lg-5,.sd-gy-lg-5{--sd-gutter-y: 3rem}.sd-g-lg-5,.sd-gx-lg-5{--sd-gutter-x: 3rem}}@media(min-width: 1200px){.sd-col-xl-auto{-ms-flex:0 0 auto;flex:0 0 auto;width:auto}.sd-col-xl-1{-ms-flex:0 0 auto;flex:0 0 auto;width:8.3333333333%}.sd-col-xl-2{-ms-flex:0 0 auto;flex:0 0 auto;width:16.6666666667%}.sd-col-xl-3{-ms-flex:0 0 auto;flex:0 0 auto;width:25%}.sd-col-xl-4{-ms-flex:0 0 auto;flex:0 0 auto;width:33.3333333333%}.sd-col-xl-5{-ms-flex:0 0 auto;flex:0 0 auto;width:41.6666666667%}.sd-col-xl-6{-ms-flex:0 0 auto;flex:0 0 auto;width:50%}.sd-col-xl-7{-ms-flex:0 0 auto;flex:0 0 auto;width:58.3333333333%}.sd-col-xl-8{-ms-flex:0 0 auto;flex:0 0 auto;width:66.6666666667%}.sd-col-xl-9{-ms-flex:0 0 auto;flex:0 0 auto;width:75%}.sd-col-xl-10{-ms-flex:0 0 auto;flex:0 0 auto;width:83.3333333333%}.sd-col-xl-11{-ms-flex:0 0 auto;flex:0 0 auto;width:91.6666666667%}.sd-col-xl-12{-ms-flex:0 0 auto;flex:0 0 auto;width:100%}.sd-g-xl-0,.sd-gy-xl-0{--sd-gutter-y: 0}.sd-g-xl-0,.sd-gx-xl-0{--sd-gutter-x: 0}.sd-g-xl-1,.sd-gy-xl-1{--sd-gutter-y: 0.25rem}.sd-g-xl-1,.sd-gx-xl-1{--sd-gutter-x: 0.25rem}.sd-g-xl-2,.sd-gy-xl-2{--sd-gutter-y: 0.5rem}.sd-g-xl-2,.sd-gx-xl-2{--sd-gutter-x: 0.5rem}.sd-g-xl-3,.sd-gy-xl-3{--sd-gutter-y: 1rem}.sd-g-xl-3,.sd-gx-xl-3{--sd-gutter-x: 1rem}.sd-g-xl-4,.sd-gy-xl-4{--sd-gutter-y: 1.5rem}.sd-g-xl-4,.sd-gx-xl-4{--sd-gutter-x: 1.5rem}.sd-g-xl-5,.sd-gy-xl-5{--sd-gutter-y: 3rem}.sd-g-xl-5,.sd-gx-xl-5{--sd-gutter-x: 3rem}}.sd-flex-row-reverse{flex-direction:row-reverse !important}details.sd-dropdown{position:relative;font-size:var(--sd-fontsize-dropdown)}details.sd-dropdown:hover{cursor:pointer}details.sd-dropdown .sd-summary-content{cursor:default}details.sd-dropdown summary.sd-summary-title{padding:.5em .6em .5em 1em;font-size:var(--sd-fontsize-dropdown-title);font-weight:var(--sd-fontweight-dropdown-title);user-select:none;-moz-user-select:none;-ms-user-select:none;-webkit-user-select:none;list-style:none;display:inline-flex;justify-content:space-between}details.sd-dropdown summary.sd-summary-title::-webkit-details-marker{display:none}details.sd-dropdown summary.sd-summary-title:focus{outline:none}details.sd-dropdown summary.sd-summary-title .sd-summary-icon{margin-right:.6em;display:inline-flex;align-items:center}details.sd-dropdown summary.sd-summary-title .sd-summary-icon svg{opacity:.8}details.sd-dropdown summary.sd-summary-title .sd-summary-text{flex-grow:1;line-height:1.5;padding-right:.5rem}details.sd-dropdown summary.sd-summary-title .sd-summary-state-marker{pointer-events:none;display:inline-flex;align-items:center}details.sd-dropdown summary.sd-summary-title .sd-summary-state-marker svg{opacity:.6}details.sd-dropdown summary.sd-summary-title:hover .sd-summary-state-marker svg{opacity:1;transform:scale(1.1)}details.sd-dropdown[open] summary .sd-octicon.no-title{visibility:hidden}details.sd-dropdown .sd-summary-chevron-right{transition:.25s}details.sd-dropdown[open]>.sd-summary-title .sd-summary-chevron-right{transform:rotate(90deg)}details.sd-dropdown[open]>.sd-summary-title .sd-summary-chevron-down{transform:rotate(180deg)}details.sd-dropdown:not([open]).sd-card{border:none}details.sd-dropdown:not([open])>.sd-card-header{border:1px solid var(--sd-color-card-border);border-radius:.25rem}details.sd-dropdown.sd-fade-in[open] summary~*{-moz-animation:sd-fade-in .5s ease-in-out;-webkit-animation:sd-fade-in .5s ease-in-out;animation:sd-fade-in .5s ease-in-out}details.sd-dropdown.sd-fade-in-slide-down[open] summary~*{-moz-animation:sd-fade-in .5s ease-in-out,sd-slide-down .5s ease-in-out;-webkit-animation:sd-fade-in .5s ease-in-out,sd-slide-down .5s ease-in-out;animation:sd-fade-in .5s ease-in-out,sd-slide-down .5s ease-in-out}.sd-col>.sd-dropdown{width:100%}.sd-summary-content>.sd-tab-set:first-child{margin-top:0}@keyframes sd-fade-in{0%{opacity:0}100%{opacity:1}}@keyframes sd-slide-down{0%{transform:translate(0, -10px)}100%{transform:translate(0, 0)}}.sd-tab-set{border-radius:.125rem;display:flex;flex-wrap:wrap;margin:1em 0;position:relative}.sd-tab-set>input{opacity:0;position:absolute}.sd-tab-set>input:checked+label{border-color:var(--sd-color-tabs-underline-active);color:var(--sd-color-tabs-label-active)}.sd-tab-set>input:checked+label+.sd-tab-content{display:block}.sd-tab-set>input:not(:checked)+label:hover{color:var(--sd-color-tabs-label-hover);border-color:var(--sd-color-tabs-underline-hover)}.sd-tab-set>input:focus+label{outline-style:auto}.sd-tab-set>input:not(.focus-visible)+label{outline:none;-webkit-tap-highlight-color:transparent}.sd-tab-set>label{border-bottom:.125rem solid transparent;margin-bottom:0;color:var(--sd-color-tabs-label-inactive);border-color:var(--sd-color-tabs-underline-inactive);cursor:pointer;font-size:var(--sd-fontsize-tabs-label);font-weight:700;padding:1em 1.25em .5em;transition:color 250ms;width:auto;z-index:1}html .sd-tab-set>label:hover{color:var(--sd-color-tabs-label-active)}.sd-col>.sd-tab-set{width:100%}.sd-tab-content{box-shadow:0 -0.0625rem var(--sd-color-tabs-overline),0 .0625rem var(--sd-color-tabs-underline);display:none;order:99;padding-bottom:.75rem;padding-top:.75rem;width:100%}.sd-tab-content>:first-child{margin-top:0 !important}.sd-tab-content>:last-child{margin-bottom:0 !important}.sd-tab-content>.sd-tab-set{margin:0}.sd-sphinx-override,.sd-sphinx-override *{-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box}.sd-sphinx-override p{margin-top:0}:root{--sd-color-primary: #0071bc;--sd-color-secondary: #6c757d;--sd-color-success: #28a745;--sd-color-info: #17a2b8;--sd-color-warning: #f0b37e;--sd-color-danger: #dc3545;--sd-color-light: #f8f9fa;--sd-color-muted: #6c757d;--sd-color-dark: #212529;--sd-color-black: black;--sd-color-white: white;--sd-color-primary-highlight: #0060a0;--sd-color-secondary-highlight: #5c636a;--sd-color-success-highlight: #228e3b;--sd-color-info-highlight: #148a9c;--sd-color-warning-highlight: #cc986b;--sd-color-danger-highlight: #bb2d3b;--sd-color-light-highlight: #d3d4d5;--sd-color-muted-highlight: #5c636a;--sd-color-dark-highlight: #1c1f23;--sd-color-black-highlight: black;--sd-color-white-highlight: #d9d9d9;--sd-color-primary-bg: rgba(0, 113, 188, 0.2);--sd-color-secondary-bg: rgba(108, 117, 125, 0.2);--sd-color-success-bg: rgba(40, 167, 69, 0.2);--sd-color-info-bg: rgba(23, 162, 184, 0.2);--sd-color-warning-bg: rgba(240, 179, 126, 0.2);--sd-color-danger-bg: rgba(220, 53, 69, 0.2);--sd-color-light-bg: rgba(248, 249, 250, 0.2);--sd-color-muted-bg: rgba(108, 117, 125, 0.2);--sd-color-dark-bg: rgba(33, 37, 41, 0.2);--sd-color-black-bg: rgba(0, 0, 0, 0.2);--sd-color-white-bg: rgba(255, 255, 255, 0.2);--sd-color-primary-text: #fff;--sd-color-secondary-text: #fff;--sd-color-success-text: #fff;--sd-color-info-text: #fff;--sd-color-warning-text: #212529;--sd-color-danger-text: #fff;--sd-color-light-text: #212529;--sd-color-muted-text: #fff;--sd-color-dark-text: #fff;--sd-color-black-text: #fff;--sd-color-white-text: #212529;--sd-color-shadow: rgba(0, 0, 0, 0.15);--sd-color-card-border: rgba(0, 0, 0, 0.125);--sd-color-card-border-hover: hsla(231, 99%, 66%, 1);--sd-color-card-background: transparent;--sd-color-card-text: inherit;--sd-color-card-header: transparent;--sd-color-card-footer: transparent;--sd-color-tabs-label-active: hsla(231, 99%, 66%, 1);--sd-color-tabs-label-hover: hsla(231, 99%, 66%, 1);--sd-color-tabs-label-inactive: hsl(0, 0%, 66%);--sd-color-tabs-underline-active: hsla(231, 99%, 66%, 1);--sd-color-tabs-underline-hover: rgba(178, 206, 245, 0.62);--sd-color-tabs-underline-inactive: transparent;--sd-color-tabs-overline: rgb(222, 222, 222);--sd-color-tabs-underline: rgb(222, 222, 222);--sd-fontsize-tabs-label: 1rem;--sd-fontsize-dropdown: inherit;--sd-fontsize-dropdown-title: 1rem;--sd-fontweight-dropdown-title: 700}
diff --git a/_static/sphinx-reports.e44b1595f1e09d5e109d001839ba3f42.css b/_static/sphinx-reports.e44b1595f1e09d5e109d001839ba3f42.css
new file mode 100644
index 0000000..02468d3
--- /dev/null
+++ b/_static/sphinx-reports.e44b1595f1e09d5e109d001839ba3f42.css
@@ -0,0 +1,48 @@
+/*
+ * Disable odd/even coloring for docutils tables if it's a coverage table.
+ * Otherwise, the 'nth-child' rule will always override row colors indicating the coverage level.
+ */
+.rst-content table.docutils:not(.field-list) tr:nth-child(2n-1) td {
+ background-color: unset;
+}
+
+/*
+ * Coloring for 0..30, 30..50, 50..80, 80..90, 90.100% coverage
+ */
+/* very good */
+.report-cov-below100 {
+ background: rgba(0, 200, 82, .4);
+}
+/* good */
+.report-cov-below90 {
+ background: rgba(0, 200, 82, .2);
+}
+/* modest */
+.report-cov-below80 {
+ background: rgba(255, 145, 0, .2);
+}
+/* bad */
+.report-cov-below50 {
+ background: rgba(255, 82, 82, .2);
+}
+/* very bad */
+.report-cov-below30 {
+ background: rgba(101, 31, 255, .2);
+}
+/* internal error */
+.report-cov-error{
+ background: rgba(255, 0, 0, .4);
+}
+
+.report-dep-summary-row {
+ font-weight: bold;
+}
+.report-codecov-summary-row {
+ font-weight: bold;
+}
+.report-doccov-summary-row {
+ font-weight: bold;
+}
+.report-unittest-summary-row {
+ font-weight: bold;
+}
diff --git a/_static/sphinx_highlight.js b/_static/sphinx_highlight.js
new file mode 100644
index 0000000..8a96c69
--- /dev/null
+++ b/_static/sphinx_highlight.js
@@ -0,0 +1,154 @@
+/* Highlighting utilities for Sphinx HTML documentation. */
+"use strict";
+
+const SPHINX_HIGHLIGHT_ENABLED = true
+
+/**
+ * highlight a given string on a node by wrapping it in
+ * span elements with the given class name.
+ */
+const _highlight = (node, addItems, text, className) => {
+ if (node.nodeType === Node.TEXT_NODE) {
+ const val = node.nodeValue;
+ const parent = node.parentNode;
+ const pos = val.toLowerCase().indexOf(text);
+ if (
+ pos >= 0 &&
+ !parent.classList.contains(className) &&
+ !parent.classList.contains("nohighlight")
+ ) {
+ let span;
+
+ const closestNode = parent.closest("body, svg, foreignObject");
+ const isInSVG = closestNode && closestNode.matches("svg");
+ if (isInSVG) {
+ span = document.createElementNS("http://www.w3.org/2000/svg", "tspan");
+ } else {
+ span = document.createElement("span");
+ span.classList.add(className);
+ }
+
+ span.appendChild(document.createTextNode(val.substr(pos, text.length)));
+ const rest = document.createTextNode(val.substr(pos + text.length));
+ parent.insertBefore(
+ span,
+ parent.insertBefore(
+ rest,
+ node.nextSibling
+ )
+ );
+ node.nodeValue = val.substr(0, pos);
+ /* There may be more occurrences of search term in this node. So call this
+ * function recursively on the remaining fragment.
+ */
+ _highlight(rest, addItems, text, className);
+
+ if (isInSVG) {
+ const rect = document.createElementNS(
+ "http://www.w3.org/2000/svg",
+ "rect"
+ );
+ const bbox = parent.getBBox();
+ rect.x.baseVal.value = bbox.x;
+ rect.y.baseVal.value = bbox.y;
+ rect.width.baseVal.value = bbox.width;
+ rect.height.baseVal.value = bbox.height;
+ rect.setAttribute("class", className);
+ addItems.push({ parent: parent, target: rect });
+ }
+ }
+ } else if (node.matches && !node.matches("button, select, textarea")) {
+ node.childNodes.forEach((el) => _highlight(el, addItems, text, className));
+ }
+};
+const _highlightText = (thisNode, text, className) => {
+ let addItems = [];
+ _highlight(thisNode, addItems, text, className);
+ addItems.forEach((obj) =>
+ obj.parent.insertAdjacentElement("beforebegin", obj.target)
+ );
+};
+
+/**
+ * Small JavaScript module for the documentation.
+ */
+const SphinxHighlight = {
+
+ /**
+ * highlight the search words provided in localstorage in the text
+ */
+ highlightSearchWords: () => {
+ if (!SPHINX_HIGHLIGHT_ENABLED) return; // bail if no highlight
+
+ // get and clear terms from localstorage
+ const url = new URL(window.location);
+ const highlight =
+ localStorage.getItem("sphinx_highlight_terms")
+ || url.searchParams.get("highlight")
+ || "";
+ localStorage.removeItem("sphinx_highlight_terms")
+ url.searchParams.delete("highlight");
+ window.history.replaceState({}, "", url);
+
+ // get individual terms from highlight string
+ const terms = highlight.toLowerCase().split(/\s+/).filter(x => x);
+ if (terms.length === 0) return; // nothing to do
+
+ // There should never be more than one element matching "div.body"
+ const divBody = document.querySelectorAll("div.body");
+ const body = divBody.length ? divBody[0] : document.querySelector("body");
+ window.setTimeout(() => {
+ terms.forEach((term) => _highlightText(body, term, "highlighted"));
+ }, 10);
+
+ const searchBox = document.getElementById("searchbox");
+ if (searchBox === null) return;
+ searchBox.appendChild(
+ document
+ .createRange()
+ .createContextualFragment(
+ '
' +
+ '' +
+ _("Hide Search Matches") +
+ "
"
+ )
+ );
+ },
+
+ /**
+ * helper function to hide the search marks again
+ */
+ hideSearchWords: () => {
+ document
+ .querySelectorAll("#searchbox .highlight-link")
+ .forEach((el) => el.remove());
+ document
+ .querySelectorAll("span.highlighted")
+ .forEach((el) => el.classList.remove("highlighted"));
+ localStorage.removeItem("sphinx_highlight_terms")
+ },
+
+ initEscapeListener: () => {
+ // only install a listener if it is really needed
+ if (!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS) return;
+
+ document.addEventListener("keydown", (event) => {
+ // bail for input elements
+ if (BLACKLISTED_KEY_CONTROL_ELEMENTS.has(document.activeElement.tagName)) return;
+ // bail with special keys
+ if (event.shiftKey || event.altKey || event.ctrlKey || event.metaKey) return;
+ if (DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS && (event.key === "Escape")) {
+ SphinxHighlight.hideSearchWords();
+ event.preventDefault();
+ }
+ });
+ },
+};
+
+_ready(() => {
+ /* Do not call highlightSearchWords() when we are on the search page.
+ * It will highlight words from the *previous* search query.
+ */
+ if (typeof Search === "undefined") SphinxHighlight.highlightSearchWords();
+ SphinxHighlight.initEscapeListener();
+});
diff --git a/_static/work-in-progress.png b/_static/work-in-progress.png
new file mode 100644
index 0000000..3e45243
Binary files /dev/null and b/_static/work-in-progress.png differ
diff --git a/coverage/class_index.html b/coverage/class_index.html
new file mode 100644
index 0000000..3c0aa47
--- /dev/null
+++ b/coverage/class_index.html
@@ -0,0 +1,133 @@
+
+
+
+
+
Code Coverage of pyEDAA.Launcher
+
+
+
+
+
+
+
+
+
+ No items found using the specified filter.
+
+
+
+
+
diff --git a/coverage/coverage_html_cb_6fb7b396.js b/coverage/coverage_html_cb_6fb7b396.js
new file mode 100644
index 0000000..1face13
--- /dev/null
+++ b/coverage/coverage_html_cb_6fb7b396.js
@@ -0,0 +1,733 @@
+// Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
+// For details: https://github.com/nedbat/coveragepy/blob/master/NOTICE.txt
+
+// Coverage.py HTML report browser code.
+/*jslint browser: true, sloppy: true, vars: true, plusplus: true, maxerr: 50, indent: 4 */
+/*global coverage: true, document, window, $ */
+
+coverage = {};
+
+// General helpers
+function debounce(callback, wait) {
+ let timeoutId = null;
+ return function(...args) {
+ clearTimeout(timeoutId);
+ timeoutId = setTimeout(() => {
+ callback.apply(this, args);
+ }, wait);
+ };
+};
+
+function checkVisible(element) {
+ const rect = element.getBoundingClientRect();
+ const viewBottom = Math.max(document.documentElement.clientHeight, window.innerHeight);
+ const viewTop = 30;
+ return !(rect.bottom < viewTop || rect.top >= viewBottom);
+}
+
+function on_click(sel, fn) {
+ const elt = document.querySelector(sel);
+ if (elt) {
+ elt.addEventListener("click", fn);
+ }
+}
+
+// Helpers for table sorting
+function getCellValue(row, column = 0) {
+ const cell = row.cells[column] // nosemgrep: eslint.detect-object-injection
+ if (cell.childElementCount == 1) {
+ var child = cell.firstElementChild;
+ if (child.tagName === "A") {
+ child = child.firstElementChild;
+ }
+ if (child instanceof HTMLDataElement && child.value) {
+ return child.value;
+ }
+ }
+ return cell.innerText || cell.textContent;
+}
+
+function rowComparator(rowA, rowB, column = 0) {
+ let valueA = getCellValue(rowA, column);
+ let valueB = getCellValue(rowB, column);
+ if (!isNaN(valueA) && !isNaN(valueB)) {
+ return valueA - valueB;
+ }
+ return valueA.localeCompare(valueB, undefined, {numeric: true});
+}
+
+function sortColumn(th) {
+ // Get the current sorting direction of the selected header,
+ // clear state on other headers and then set the new sorting direction.
+ const currentSortOrder = th.getAttribute("aria-sort");
+ [...th.parentElement.cells].forEach(header => header.setAttribute("aria-sort", "none"));
+ var direction;
+ if (currentSortOrder === "none") {
+ direction = th.dataset.defaultSortOrder || "ascending";
+ }
+ else if (currentSortOrder === "ascending") {
+ direction = "descending";
+ }
+ else {
+ direction = "ascending";
+ }
+ th.setAttribute("aria-sort", direction);
+
+ const column = [...th.parentElement.cells].indexOf(th)
+
+ // Sort all rows and afterwards append them in order to move them in the DOM.
+ Array.from(th.closest("table").querySelectorAll("tbody tr"))
+ .sort((rowA, rowB) => rowComparator(rowA, rowB, column) * (direction === "ascending" ? 1 : -1))
+ .forEach(tr => tr.parentElement.appendChild(tr));
+
+ // Save the sort order for next time.
+ if (th.id !== "region") {
+ let th_id = "file"; // Sort by file if we don't have a column id
+ let current_direction = direction;
+ const stored_list = localStorage.getItem(coverage.INDEX_SORT_STORAGE);
+ if (stored_list) {
+ ({th_id, direction} = JSON.parse(stored_list))
+ }
+ localStorage.setItem(coverage.INDEX_SORT_STORAGE, JSON.stringify({
+ "th_id": th.id,
+ "direction": current_direction
+ }));
+ if (th.id !== th_id || document.getElementById("region")) {
+ // Sort column has changed, unset sorting by function or class.
+ localStorage.setItem(coverage.SORTED_BY_REGION, JSON.stringify({
+ "by_region": false,
+ "region_direction": current_direction
+ }));
+ }
+ }
+ else {
+ // Sort column has changed to by function or class, remember that.
+ localStorage.setItem(coverage.SORTED_BY_REGION, JSON.stringify({
+ "by_region": true,
+ "region_direction": direction
+ }));
+ }
+}
+
+// Find all the elements with data-shortcut attribute, and use them to assign a shortcut key.
+coverage.assign_shortkeys = function () {
+ document.querySelectorAll("[data-shortcut]").forEach(element => {
+ document.addEventListener("keypress", event => {
+ if (event.target.tagName.toLowerCase() === "input") {
+ return; // ignore keypress from search filter
+ }
+ if (event.key === element.dataset.shortcut) {
+ element.click();
+ }
+ });
+ });
+};
+
+// Create the events for the filter box.
+coverage.wire_up_filter = function () {
+ // Populate the filter and hide100 inputs if there are saved values for them.
+ const saved_filter_value = localStorage.getItem(coverage.FILTER_STORAGE);
+ if (saved_filter_value) {
+ document.getElementById("filter").value = saved_filter_value;
+ }
+ const saved_hide100_value = localStorage.getItem(coverage.HIDE100_STORAGE);
+ if (saved_hide100_value) {
+ document.getElementById("hide100").checked = JSON.parse(saved_hide100_value);
+ }
+
+ // Cache elements.
+ const table = document.querySelector("table.index");
+ const table_body_rows = table.querySelectorAll("tbody tr");
+ const no_rows = document.getElementById("no_rows");
+
+ // Observe filter keyevents.
+ const filter_handler = (event => {
+ // Keep running total of each metric, first index contains number of shown rows
+ const totals = new Array(table.rows[0].cells.length).fill(0);
+ // Accumulate the percentage as fraction
+ totals[totals.length - 1] = { "numer": 0, "denom": 0 }; // nosemgrep: eslint.detect-object-injection
+
+ var text = document.getElementById("filter").value;
+ // Store filter value
+ localStorage.setItem(coverage.FILTER_STORAGE, text);
+ const casefold = (text === text.toLowerCase());
+ const hide100 = document.getElementById("hide100").checked;
+ // Store hide value.
+ localStorage.setItem(coverage.HIDE100_STORAGE, JSON.stringify(hide100));
+
+ // Hide / show elements.
+ table_body_rows.forEach(row => {
+ var show = false;
+ // Check the text filter.
+ for (let column = 0; column < totals.length; column++) {
+ cell = row.cells[column];
+ if (cell.classList.contains("name")) {
+ var celltext = cell.textContent;
+ if (casefold) {
+ celltext = celltext.toLowerCase();
+ }
+ if (celltext.includes(text)) {
+ show = true;
+ }
+ }
+ }
+
+ // Check the "hide covered" filter.
+ if (show && hide100) {
+ const [numer, denom] = row.cells[row.cells.length - 1].dataset.ratio.split(" ");
+ show = (numer !== denom);
+ }
+
+ if (!show) {
+ // hide
+ row.classList.add("hidden");
+ return;
+ }
+
+ // show
+ row.classList.remove("hidden");
+ totals[0]++;
+
+ for (let column = 0; column < totals.length; column++) {
+ // Accumulate dynamic totals
+ cell = row.cells[column] // nosemgrep: eslint.detect-object-injection
+ if (cell.classList.contains("name")) {
+ continue;
+ }
+ if (column === totals.length - 1) {
+ // Last column contains percentage
+ const [numer, denom] = cell.dataset.ratio.split(" ");
+ totals[column]["numer"] += parseInt(numer, 10); // nosemgrep: eslint.detect-object-injection
+ totals[column]["denom"] += parseInt(denom, 10); // nosemgrep: eslint.detect-object-injection
+ }
+ else {
+ totals[column] += parseInt(cell.textContent, 10); // nosemgrep: eslint.detect-object-injection
+ }
+ }
+ });
+
+ // Show placeholder if no rows will be displayed.
+ if (!totals[0]) {
+ // Show placeholder, hide table.
+ no_rows.style.display = "block";
+ table.style.display = "none";
+ return;
+ }
+
+ // Hide placeholder, show table.
+ no_rows.style.display = null;
+ table.style.display = null;
+
+ const footer = table.tFoot.rows[0];
+ // Calculate new dynamic sum values based on visible rows.
+ for (let column = 0; column < totals.length; column++) {
+ // Get footer cell element.
+ const cell = footer.cells[column]; // nosemgrep: eslint.detect-object-injection
+ if (cell.classList.contains("name")) {
+ continue;
+ }
+
+ // Set value into dynamic footer cell element.
+ if (column === totals.length - 1) {
+ // Percentage column uses the numerator and denominator,
+ // and adapts to the number of decimal places.
+ const match = /\.([0-9]+)/.exec(cell.textContent);
+ const places = match ? match[1].length : 0;
+ const { numer, denom } = totals[column]; // nosemgrep: eslint.detect-object-injection
+ cell.dataset.ratio = `${numer} ${denom}`;
+ // Check denom to prevent NaN if filtered files contain no statements
+ cell.textContent = denom
+ ? `${(numer * 100 / denom).toFixed(places)}%`
+ : `${(100).toFixed(places)}%`;
+ }
+ else {
+ cell.textContent = totals[column]; // nosemgrep: eslint.detect-object-injection
+ }
+ }
+ });
+
+ document.getElementById("filter").addEventListener("input", debounce(filter_handler));
+ document.getElementById("hide100").addEventListener("input", debounce(filter_handler));
+
+ // Trigger change event on setup, to force filter on page refresh
+ // (filter value may still be present).
+ document.getElementById("filter").dispatchEvent(new Event("input"));
+ document.getElementById("hide100").dispatchEvent(new Event("input"));
+};
+coverage.FILTER_STORAGE = "COVERAGE_FILTER_VALUE";
+coverage.HIDE100_STORAGE = "COVERAGE_HIDE100_VALUE";
+
+// Set up the click-to-sort columns.
+coverage.wire_up_sorting = function () {
+ document.querySelectorAll("[data-sortable] th[aria-sort]").forEach(
+ th => th.addEventListener("click", e => sortColumn(e.target))
+ );
+
+ // Look for a localStorage item containing previous sort settings:
+ let th_id = "file", direction = "ascending";
+ const stored_list = localStorage.getItem(coverage.INDEX_SORT_STORAGE);
+ if (stored_list) {
+ ({th_id, direction} = JSON.parse(stored_list));
+ }
+ let by_region = false, region_direction = "ascending";
+ const sorted_by_region = localStorage.getItem(coverage.SORTED_BY_REGION);
+ if (sorted_by_region) {
+ ({
+ by_region,
+ region_direction
+ } = JSON.parse(sorted_by_region));
+ }
+
+ const region_id = "region";
+ if (by_region && document.getElementById(region_id)) {
+ direction = region_direction;
+ }
+ // If we are in a page that has a column with id of "region", sort on
+ // it if the last sort was by function or class.
+ let th;
+ if (document.getElementById(region_id)) {
+ th = document.getElementById(by_region ? region_id : th_id);
+ }
+ else {
+ th = document.getElementById(th_id);
+ }
+ th.setAttribute("aria-sort", direction === "ascending" ? "descending" : "ascending");
+ th.click()
+};
+
+coverage.INDEX_SORT_STORAGE = "COVERAGE_INDEX_SORT_2";
+coverage.SORTED_BY_REGION = "COVERAGE_SORT_REGION";
+
+// Loaded on index.html
+coverage.index_ready = function () {
+ coverage.assign_shortkeys();
+ coverage.wire_up_filter();
+ coverage.wire_up_sorting();
+
+ on_click(".button_prev_file", coverage.to_prev_file);
+ on_click(".button_next_file", coverage.to_next_file);
+
+ on_click(".button_show_hide_help", coverage.show_hide_help);
+};
+
+// -- pyfile stuff --
+
+coverage.LINE_FILTERS_STORAGE = "COVERAGE_LINE_FILTERS";
+
+coverage.pyfile_ready = function () {
+ // If we're directed to a particular line number, highlight the line.
+ var frag = location.hash;
+ if (frag.length > 2 && frag[1] === "t") {
+ document.querySelector(frag).closest(".n").classList.add("highlight");
+ coverage.set_sel(parseInt(frag.substr(2), 10));
+ }
+ else {
+ coverage.set_sel(0);
+ }
+
+ on_click(".button_toggle_run", coverage.toggle_lines);
+ on_click(".button_toggle_mis", coverage.toggle_lines);
+ on_click(".button_toggle_exc", coverage.toggle_lines);
+ on_click(".button_toggle_par", coverage.toggle_lines);
+
+ on_click(".button_next_chunk", coverage.to_next_chunk_nicely);
+ on_click(".button_prev_chunk", coverage.to_prev_chunk_nicely);
+ on_click(".button_top_of_page", coverage.to_top);
+ on_click(".button_first_chunk", coverage.to_first_chunk);
+
+ on_click(".button_prev_file", coverage.to_prev_file);
+ on_click(".button_next_file", coverage.to_next_file);
+ on_click(".button_to_index", coverage.to_index);
+
+ on_click(".button_show_hide_help", coverage.show_hide_help);
+
+ coverage.filters = undefined;
+ try {
+ coverage.filters = localStorage.getItem(coverage.LINE_FILTERS_STORAGE);
+ } catch(err) {}
+
+ if (coverage.filters) {
+ coverage.filters = JSON.parse(coverage.filters);
+ }
+ else {
+ coverage.filters = {run: false, exc: true, mis: true, par: true};
+ }
+
+ for (cls in coverage.filters) {
+ coverage.set_line_visibilty(cls, coverage.filters[cls]); // nosemgrep: eslint.detect-object-injection
+ }
+
+ coverage.assign_shortkeys();
+ coverage.init_scroll_markers();
+ coverage.wire_up_sticky_header();
+
+ document.querySelectorAll("[id^=ctxs]").forEach(
+ cbox => cbox.addEventListener("click", coverage.expand_contexts)
+ );
+
+ // Rebuild scroll markers when the window height changes.
+ window.addEventListener("resize", coverage.build_scroll_markers);
+};
+
+coverage.toggle_lines = function (event) {
+ const btn = event.target.closest("button");
+ const category = btn.value
+ const show = !btn.classList.contains("show_" + category);
+ coverage.set_line_visibilty(category, show);
+ coverage.build_scroll_markers();
+ coverage.filters[category] = show;
+ try {
+ localStorage.setItem(coverage.LINE_FILTERS_STORAGE, JSON.stringify(coverage.filters));
+ } catch(err) {}
+};
+
+coverage.set_line_visibilty = function (category, should_show) {
+ const cls = "show_" + category;
+ const btn = document.querySelector(".button_toggle_" + category);
+ if (btn) {
+ if (should_show) {
+ document.querySelectorAll("#source ." + category).forEach(e => e.classList.add(cls));
+ btn.classList.add(cls);
+ }
+ else {
+ document.querySelectorAll("#source ." + category).forEach(e => e.classList.remove(cls));
+ btn.classList.remove(cls);
+ }
+ }
+};
+
+// Return the nth line div.
+coverage.line_elt = function (n) {
+ return document.getElementById("t" + n)?.closest("p");
+};
+
+// Set the selection. b and e are line numbers.
+coverage.set_sel = function (b, e) {
+ // The first line selected.
+ coverage.sel_begin = b;
+ // The next line not selected.
+ coverage.sel_end = (e === undefined) ? b+1 : e;
+};
+
+coverage.to_top = function () {
+ coverage.set_sel(0, 1);
+ coverage.scroll_window(0);
+};
+
+coverage.to_first_chunk = function () {
+ coverage.set_sel(0, 1);
+ coverage.to_next_chunk();
+};
+
+coverage.to_prev_file = function () {
+ window.location = document.getElementById("prevFileLink").href;
+}
+
+coverage.to_next_file = function () {
+ window.location = document.getElementById("nextFileLink").href;
+}
+
+coverage.to_index = function () {
+ location.href = document.getElementById("indexLink").href;
+}
+
+coverage.show_hide_help = function () {
+ const helpCheck = document.getElementById("help_panel_state")
+ helpCheck.checked = !helpCheck.checked;
+}
+
+// Return a string indicating what kind of chunk this line belongs to,
+// or null if not a chunk.
+coverage.chunk_indicator = function (line_elt) {
+ const classes = line_elt?.className;
+ if (!classes) {
+ return null;
+ }
+ const match = classes.match(/\bshow_\w+\b/);
+ if (!match) {
+ return null;
+ }
+ return match[0];
+};
+
+coverage.to_next_chunk = function () {
+ const c = coverage;
+
+ // Find the start of the next colored chunk.
+ var probe = c.sel_end;
+ var chunk_indicator, probe_line;
+ while (true) {
+ probe_line = c.line_elt(probe);
+ if (!probe_line) {
+ return;
+ }
+ chunk_indicator = c.chunk_indicator(probe_line);
+ if (chunk_indicator) {
+ break;
+ }
+ probe++;
+ }
+
+ // There's a next chunk, `probe` points to it.
+ var begin = probe;
+
+ // Find the end of this chunk.
+ var next_indicator = chunk_indicator;
+ while (next_indicator === chunk_indicator) {
+ probe++;
+ probe_line = c.line_elt(probe);
+ next_indicator = c.chunk_indicator(probe_line);
+ }
+ c.set_sel(begin, probe);
+ c.show_selection();
+};
+
+coverage.to_prev_chunk = function () {
+ const c = coverage;
+
+ // Find the end of the prev colored chunk.
+ var probe = c.sel_begin-1;
+ var probe_line = c.line_elt(probe);
+ if (!probe_line) {
+ return;
+ }
+ var chunk_indicator = c.chunk_indicator(probe_line);
+ while (probe > 1 && !chunk_indicator) {
+ probe--;
+ probe_line = c.line_elt(probe);
+ if (!probe_line) {
+ return;
+ }
+ chunk_indicator = c.chunk_indicator(probe_line);
+ }
+
+ // There's a prev chunk, `probe` points to its last line.
+ var end = probe+1;
+
+ // Find the beginning of this chunk.
+ var prev_indicator = chunk_indicator;
+ while (prev_indicator === chunk_indicator) {
+ probe--;
+ if (probe <= 0) {
+ return;
+ }
+ probe_line = c.line_elt(probe);
+ prev_indicator = c.chunk_indicator(probe_line);
+ }
+ c.set_sel(probe+1, end);
+ c.show_selection();
+};
+
+// Returns 0, 1, or 2: how many of the two ends of the selection are on
+// the screen right now?
+coverage.selection_ends_on_screen = function () {
+ if (coverage.sel_begin === 0) {
+ return 0;
+ }
+
+ const begin = coverage.line_elt(coverage.sel_begin);
+ const end = coverage.line_elt(coverage.sel_end-1);
+
+ return (
+ (checkVisible(begin) ? 1 : 0)
+ + (checkVisible(end) ? 1 : 0)
+ );
+};
+
+coverage.to_next_chunk_nicely = function () {
+ if (coverage.selection_ends_on_screen() === 0) {
+ // The selection is entirely off the screen:
+ // Set the top line on the screen as selection.
+
+ // This will select the top-left of the viewport
+ // As this is most likely the span with the line number we take the parent
+ const line = document.elementFromPoint(0, 0).parentElement;
+ if (line.parentElement !== document.getElementById("source")) {
+ // The element is not a source line but the header or similar
+ coverage.select_line_or_chunk(1);
+ }
+ else {
+ // We extract the line number from the id
+ coverage.select_line_or_chunk(parseInt(line.id.substring(1), 10));
+ }
+ }
+ coverage.to_next_chunk();
+};
+
+coverage.to_prev_chunk_nicely = function () {
+ if (coverage.selection_ends_on_screen() === 0) {
+ // The selection is entirely off the screen:
+ // Set the lowest line on the screen as selection.
+
+ // This will select the bottom-left of the viewport
+ // As this is most likely the span with the line number we take the parent
+ const line = document.elementFromPoint(document.documentElement.clientHeight-1, 0).parentElement;
+ if (line.parentElement !== document.getElementById("source")) {
+ // The element is not a source line but the header or similar
+ coverage.select_line_or_chunk(coverage.lines_len);
+ }
+ else {
+ // We extract the line number from the id
+ coverage.select_line_or_chunk(parseInt(line.id.substring(1), 10));
+ }
+ }
+ coverage.to_prev_chunk();
+};
+
+// Select line number lineno, or if it is in a colored chunk, select the
+// entire chunk
+coverage.select_line_or_chunk = function (lineno) {
+ var c = coverage;
+ var probe_line = c.line_elt(lineno);
+ if (!probe_line) {
+ return;
+ }
+ var the_indicator = c.chunk_indicator(probe_line);
+ if (the_indicator) {
+ // The line is in a highlighted chunk.
+ // Search backward for the first line.
+ var probe = lineno;
+ var indicator = the_indicator;
+ while (probe > 0 && indicator === the_indicator) {
+ probe--;
+ probe_line = c.line_elt(probe);
+ if (!probe_line) {
+ break;
+ }
+ indicator = c.chunk_indicator(probe_line);
+ }
+ var begin = probe + 1;
+
+ // Search forward for the last line.
+ probe = lineno;
+ indicator = the_indicator;
+ while (indicator === the_indicator) {
+ probe++;
+ probe_line = c.line_elt(probe);
+ indicator = c.chunk_indicator(probe_line);
+ }
+
+ coverage.set_sel(begin, probe);
+ }
+ else {
+ coverage.set_sel(lineno);
+ }
+};
+
+coverage.show_selection = function () {
+ // Highlight the lines in the chunk
+ document.querySelectorAll("#source .highlight").forEach(e => e.classList.remove("highlight"));
+ for (let probe = coverage.sel_begin; probe < coverage.sel_end; probe++) {
+ coverage.line_elt(probe).querySelector(".n").classList.add("highlight");
+ }
+
+ coverage.scroll_to_selection();
+};
+
+coverage.scroll_to_selection = function () {
+ // Scroll the page if the chunk isn't fully visible.
+ if (coverage.selection_ends_on_screen() < 2) {
+ const element = coverage.line_elt(coverage.sel_begin);
+ coverage.scroll_window(element.offsetTop - 60);
+ }
+};
+
+coverage.scroll_window = function (to_pos) {
+ window.scroll({top: to_pos, behavior: "smooth"});
+};
+
+coverage.init_scroll_markers = function () {
+ // Init some variables
+ coverage.lines_len = document.querySelectorAll("#source > p").length;
+
+ // Build html
+ coverage.build_scroll_markers();
+};
+
+coverage.build_scroll_markers = function () {
+ const temp_scroll_marker = document.getElementById("scroll_marker")
+ if (temp_scroll_marker) temp_scroll_marker.remove();
+ // Don't build markers if the window has no scroll bar.
+ if (document.body.scrollHeight <= window.innerHeight) {
+ return;
+ }
+
+ const marker_scale = window.innerHeight / document.body.scrollHeight;
+ const line_height = Math.min(Math.max(3, window.innerHeight / coverage.lines_len), 10);
+
+ let previous_line = -99, last_mark, last_top;
+
+ const scroll_marker = document.createElement("div");
+ scroll_marker.id = "scroll_marker";
+ document.getElementById("source").querySelectorAll(
+ "p.show_run, p.show_mis, p.show_exc, p.show_exc, p.show_par"
+ ).forEach(element => {
+ const line_top = Math.floor(element.offsetTop * marker_scale);
+ const line_number = parseInt(element.querySelector(".n a").id.substr(1));
+
+ if (line_number === previous_line + 1) {
+ // If this solid missed block just make previous mark higher.
+ last_mark.style.height = `${line_top + line_height - last_top}px`;
+ }
+ else {
+ // Add colored line in scroll_marker block.
+ last_mark = document.createElement("div");
+ last_mark.id = `m${line_number}`;
+ last_mark.classList.add("marker");
+ last_mark.style.height = `${line_height}px`;
+ last_mark.style.top = `${line_top}px`;
+ scroll_marker.append(last_mark);
+ last_top = line_top;
+ }
+
+ previous_line = line_number;
+ });
+
+ // Append last to prevent layout calculation
+ document.body.append(scroll_marker);
+};
+
+coverage.wire_up_sticky_header = function () {
+ const header = document.querySelector("header");
+ const header_bottom = (
+ header.querySelector(".content h2").getBoundingClientRect().top -
+ header.getBoundingClientRect().top
+ );
+
+ function updateHeader() {
+ if (window.scrollY > header_bottom) {
+ header.classList.add("sticky");
+ }
+ else {
+ header.classList.remove("sticky");
+ }
+ }
+
+ window.addEventListener("scroll", updateHeader);
+ updateHeader();
+};
+
+coverage.expand_contexts = function (e) {
+ var ctxs = e.target.parentNode.querySelector(".ctxs");
+
+ if (!ctxs.classList.contains("expanded")) {
+ var ctxs_text = ctxs.textContent;
+ var width = Number(ctxs_text[0]);
+ ctxs.textContent = "";
+ for (var i = 1; i < ctxs_text.length; i += width) {
+ key = ctxs_text.substring(i, i + width).trim();
+ ctxs.appendChild(document.createTextNode(contexts[key]));
+ ctxs.appendChild(document.createElement("br"));
+ }
+ ctxs.classList.add("expanded");
+ }
+};
+
+document.addEventListener("DOMContentLoaded", () => {
+ if (document.body.classList.contains("indexfile")) {
+ coverage.index_ready();
+ }
+ else {
+ coverage.pyfile_ready();
+ }
+});
diff --git a/coverage/favicon_32_cb_58284776.png b/coverage/favicon_32_cb_58284776.png
new file mode 100644
index 0000000..8649f04
Binary files /dev/null and b/coverage/favicon_32_cb_58284776.png differ
diff --git a/coverage/function_index.html b/coverage/function_index.html
new file mode 100644
index 0000000..b7279eb
--- /dev/null
+++ b/coverage/function_index.html
@@ -0,0 +1,183 @@
+
+
+
+
+
Code Coverage of pyEDAA.Launcher
+
+
+
+
+
+
+
+
+
+ No items found using the specified filter.
+
+
+
+
+
diff --git a/coverage/index.html b/coverage/index.html
new file mode 100644
index 0000000..9b530c8
--- /dev/null
+++ b/coverage/index.html
@@ -0,0 +1,119 @@
+
+
+
+
+
Code Coverage of pyEDAA.Launcher
+
+
+
+
+
+
+
+
+
+
+ File
+ statements
+ missing
+ excluded
+ branches
+ partial
+ coverage
+
+
+
+
+ pyEDAA/Launcher/__init__.py
+ 80
+ 43
+ 0
+ 22
+ 3
+ 41%
+
+
+
+
+ Total
+ 80
+ 43
+ 0
+ 22
+ 3
+ 41%
+
+
+
+
+ No items found using the specified filter.
+
+
+
+
+
diff --git a/coverage/keybd_closed_cb_ce680311.png b/coverage/keybd_closed_cb_ce680311.png
new file mode 100644
index 0000000..ba119c4
Binary files /dev/null and b/coverage/keybd_closed_cb_ce680311.png differ
diff --git a/coverage/status.json b/coverage/status.json
new file mode 100644
index 0000000..41901f0
--- /dev/null
+++ b/coverage/status.json
@@ -0,0 +1 @@
+{"note":"This file is an internal implementation detail to speed up HTML report generation. Its format can change at any time. You might be looking for the JSON report: https://coverage.rtfd.io/cmd.html#cmd-json","format":5,"version":"7.6.7","globals":"2ccd7bc4cdb6be51a658cd6d8e56a415","files":{"z_0b97c06fcb6623f7___init___py":{"hash":"eec101476a8aae5e20ef0084067bb3a3","index":{"url":"z_0b97c06fcb6623f7___init___py.html","file":"pyEDAA/Launcher/__init__.py","description":"","nums":{"precision":0,"n_files":1,"n_statements":80,"n_excluded":0,"n_missing":43,"n_branches":22,"n_partial_branches":3,"n_missing_branches":17}}}}}
\ No newline at end of file
diff --git a/coverage/style_cb_8e611ae1.css b/coverage/style_cb_8e611ae1.css
new file mode 100644
index 0000000..3cdaf05
--- /dev/null
+++ b/coverage/style_cb_8e611ae1.css
@@ -0,0 +1,337 @@
+@charset "UTF-8";
+/* Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0 */
+/* For details: https://github.com/nedbat/coveragepy/blob/master/NOTICE.txt */
+/* Don't edit this .css file. Edit the .scss file instead! */
+html, body, h1, h2, h3, p, table, td, th { margin: 0; padding: 0; border: 0; font-weight: inherit; font-style: inherit; font-size: 100%; font-family: inherit; vertical-align: baseline; }
+
+body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; font-size: 1em; background: #fff; color: #000; }
+
+@media (prefers-color-scheme: dark) { body { background: #1e1e1e; } }
+
+@media (prefers-color-scheme: dark) { body { color: #eee; } }
+
+html > body { font-size: 16px; }
+
+a:active, a:focus { outline: 2px dashed #007acc; }
+
+p { font-size: .875em; line-height: 1.4em; }
+
+table { border-collapse: collapse; }
+
+td { vertical-align: top; }
+
+table tr.hidden { display: none !important; }
+
+p#no_rows { display: none; font-size: 1.15em; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; }
+
+a.nav { text-decoration: none; color: inherit; }
+
+a.nav:hover { text-decoration: underline; color: inherit; }
+
+.hidden { display: none; }
+
+header { background: #f8f8f8; width: 100%; z-index: 2; border-bottom: 1px solid #ccc; }
+
+@media (prefers-color-scheme: dark) { header { background: black; } }
+
+@media (prefers-color-scheme: dark) { header { border-color: #333; } }
+
+header .content { padding: 1rem 3.5rem; }
+
+header h2 { margin-top: .5em; font-size: 1em; }
+
+header h2 a.button { font-family: inherit; font-size: inherit; border: 1px solid; border-radius: .2em; background: #eee; color: inherit; text-decoration: none; padding: .1em .5em; margin: 1px calc(.1em + 1px); cursor: pointer; border-color: #ccc; }
+
+@media (prefers-color-scheme: dark) { header h2 a.button { background: #333; } }
+
+@media (prefers-color-scheme: dark) { header h2 a.button { border-color: #444; } }
+
+header h2 a.button.current { border: 2px solid; background: #fff; border-color: #999; cursor: default; }
+
+@media (prefers-color-scheme: dark) { header h2 a.button.current { background: #1e1e1e; } }
+
+@media (prefers-color-scheme: dark) { header h2 a.button.current { border-color: #777; } }
+
+header p.text { margin: .5em 0 -.5em; color: #666; font-style: italic; }
+
+@media (prefers-color-scheme: dark) { header p.text { color: #aaa; } }
+
+header.sticky { position: fixed; left: 0; right: 0; height: 2.5em; }
+
+header.sticky .text { display: none; }
+
+header.sticky h1, header.sticky h2 { font-size: 1em; margin-top: 0; display: inline-block; }
+
+header.sticky .content { padding: 0.5rem 3.5rem; }
+
+header.sticky .content p { font-size: 1em; }
+
+header.sticky ~ #source { padding-top: 6.5em; }
+
+main { position: relative; z-index: 1; }
+
+footer { margin: 1rem 3.5rem; }
+
+footer .content { padding: 0; color: #666; font-style: italic; }
+
+@media (prefers-color-scheme: dark) { footer .content { color: #aaa; } }
+
+#index { margin: 1rem 0 0 3.5rem; }
+
+h1 { font-size: 1.25em; display: inline-block; }
+
+#filter_container { float: right; margin: 0 2em 0 0; line-height: 1.66em; }
+
+#filter_container #filter { width: 10em; padding: 0.2em 0.5em; border: 2px solid #ccc; background: #fff; color: #000; }
+
+@media (prefers-color-scheme: dark) { #filter_container #filter { border-color: #444; } }
+
+@media (prefers-color-scheme: dark) { #filter_container #filter { background: #1e1e1e; } }
+
+@media (prefers-color-scheme: dark) { #filter_container #filter { color: #eee; } }
+
+#filter_container #filter:focus { border-color: #007acc; }
+
+#filter_container :disabled ~ label { color: #ccc; }
+
+@media (prefers-color-scheme: dark) { #filter_container :disabled ~ label { color: #444; } }
+
+#filter_container label { font-size: .875em; color: #666; }
+
+@media (prefers-color-scheme: dark) { #filter_container label { color: #aaa; } }
+
+header button { font-family: inherit; font-size: inherit; border: 1px solid; border-radius: .2em; background: #eee; color: inherit; text-decoration: none; padding: .1em .5em; margin: 1px calc(.1em + 1px); cursor: pointer; border-color: #ccc; }
+
+@media (prefers-color-scheme: dark) { header button { background: #333; } }
+
+@media (prefers-color-scheme: dark) { header button { border-color: #444; } }
+
+header button:active, header button:focus { outline: 2px dashed #007acc; }
+
+header button.run { background: #eeffee; }
+
+@media (prefers-color-scheme: dark) { header button.run { background: #373d29; } }
+
+header button.run.show_run { background: #dfd; border: 2px solid #00dd00; margin: 0 .1em; }
+
+@media (prefers-color-scheme: dark) { header button.run.show_run { background: #373d29; } }
+
+header button.mis { background: #ffeeee; }
+
+@media (prefers-color-scheme: dark) { header button.mis { background: #4b1818; } }
+
+header button.mis.show_mis { background: #fdd; border: 2px solid #ff0000; margin: 0 .1em; }
+
+@media (prefers-color-scheme: dark) { header button.mis.show_mis { background: #4b1818; } }
+
+header button.exc { background: #f7f7f7; }
+
+@media (prefers-color-scheme: dark) { header button.exc { background: #333; } }
+
+header button.exc.show_exc { background: #eee; border: 2px solid #808080; margin: 0 .1em; }
+
+@media (prefers-color-scheme: dark) { header button.exc.show_exc { background: #333; } }
+
+header button.par { background: #ffffd5; }
+
+@media (prefers-color-scheme: dark) { header button.par { background: #650; } }
+
+header button.par.show_par { background: #ffa; border: 2px solid #bbbb00; margin: 0 .1em; }
+
+@media (prefers-color-scheme: dark) { header button.par.show_par { background: #650; } }
+
+#help_panel, #source p .annotate.long { display: none; position: absolute; z-index: 999; background: #ffffcc; border: 1px solid #888; border-radius: .2em; color: #333; padding: .25em .5em; }
+
+#source p .annotate.long { white-space: normal; float: right; top: 1.75em; right: 1em; height: auto; }
+
+#help_panel_wrapper { float: right; position: relative; }
+
+#keyboard_icon { margin: 5px; }
+
+#help_panel_state { display: none; }
+
+#help_panel { top: 25px; right: 0; padding: .75em; border: 1px solid #883; color: #333; }
+
+#help_panel .keyhelp p { margin-top: .75em; }
+
+#help_panel .legend { font-style: italic; margin-bottom: 1em; }
+
+.indexfile #help_panel { width: 25em; }
+
+.pyfile #help_panel { width: 18em; }
+
+#help_panel_state:checked ~ #help_panel { display: block; }
+
+kbd { border: 1px solid black; border-color: #888 #333 #333 #888; padding: .1em .35em; font-family: SFMono-Regular, Menlo, Monaco, Consolas, monospace; font-weight: bold; background: #eee; border-radius: 3px; }
+
+#source { padding: 1em 0 1em 3.5rem; font-family: SFMono-Regular, Menlo, Monaco, Consolas, monospace; }
+
+#source p { position: relative; white-space: pre; }
+
+#source p * { box-sizing: border-box; }
+
+#source p .n { float: left; text-align: right; width: 3.5rem; box-sizing: border-box; margin-left: -3.5rem; padding-right: 1em; color: #999; user-select: none; }
+
+@media (prefers-color-scheme: dark) { #source p .n { color: #777; } }
+
+#source p .n.highlight { background: #ffdd00; }
+
+#source p .n a { scroll-margin-top: 6em; text-decoration: none; color: #999; }
+
+@media (prefers-color-scheme: dark) { #source p .n a { color: #777; } }
+
+#source p .n a:hover { text-decoration: underline; color: #999; }
+
+@media (prefers-color-scheme: dark) { #source p .n a:hover { color: #777; } }
+
+#source p .t { display: inline-block; width: 100%; box-sizing: border-box; margin-left: -.5em; padding-left: 0.3em; border-left: 0.2em solid #fff; }
+
+@media (prefers-color-scheme: dark) { #source p .t { border-color: #1e1e1e; } }
+
+#source p .t:hover { background: #f2f2f2; }
+
+@media (prefers-color-scheme: dark) { #source p .t:hover { background: #282828; } }
+
+#source p .t:hover ~ .r .annotate.long { display: block; }
+
+#source p .t .com { color: #008000; font-style: italic; line-height: 1px; }
+
+@media (prefers-color-scheme: dark) { #source p .t .com { color: #6a9955; } }
+
+#source p .t .key { font-weight: bold; line-height: 1px; }
+
+#source p .t .str { color: #0451a5; }
+
+@media (prefers-color-scheme: dark) { #source p .t .str { color: #9cdcfe; } }
+
+#source p.mis .t { border-left: 0.2em solid #ff0000; }
+
+#source p.mis.show_mis .t { background: #fdd; }
+
+@media (prefers-color-scheme: dark) { #source p.mis.show_mis .t { background: #4b1818; } }
+
+#source p.mis.show_mis .t:hover { background: #f2d2d2; }
+
+@media (prefers-color-scheme: dark) { #source p.mis.show_mis .t:hover { background: #532323; } }
+
+#source p.run .t { border-left: 0.2em solid #00dd00; }
+
+#source p.run.show_run .t { background: #dfd; }
+
+@media (prefers-color-scheme: dark) { #source p.run.show_run .t { background: #373d29; } }
+
+#source p.run.show_run .t:hover { background: #d2f2d2; }
+
+@media (prefers-color-scheme: dark) { #source p.run.show_run .t:hover { background: #404633; } }
+
+#source p.exc .t { border-left: 0.2em solid #808080; }
+
+#source p.exc.show_exc .t { background: #eee; }
+
+@media (prefers-color-scheme: dark) { #source p.exc.show_exc .t { background: #333; } }
+
+#source p.exc.show_exc .t:hover { background: #e2e2e2; }
+
+@media (prefers-color-scheme: dark) { #source p.exc.show_exc .t:hover { background: #3c3c3c; } }
+
+#source p.par .t { border-left: 0.2em solid #bbbb00; }
+
+#source p.par.show_par .t { background: #ffa; }
+
+@media (prefers-color-scheme: dark) { #source p.par.show_par .t { background: #650; } }
+
+#source p.par.show_par .t:hover { background: #f2f2a2; }
+
+@media (prefers-color-scheme: dark) { #source p.par.show_par .t:hover { background: #6d5d0c; } }
+
+#source p .r { position: absolute; top: 0; right: 2.5em; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; }
+
+#source p .annotate { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; color: #666; padding-right: .5em; }
+
+@media (prefers-color-scheme: dark) { #source p .annotate { color: #ddd; } }
+
+#source p .annotate.short:hover ~ .long { display: block; }
+
+#source p .annotate.long { width: 30em; right: 2.5em; }
+
+#source p input { display: none; }
+
+#source p input ~ .r label.ctx { cursor: pointer; border-radius: .25em; }
+
+#source p input ~ .r label.ctx::before { content: "▶ "; }
+
+#source p input ~ .r label.ctx:hover { background: #e8f4ff; color: #666; }
+
+@media (prefers-color-scheme: dark) { #source p input ~ .r label.ctx:hover { background: #0f3a42; } }
+
+@media (prefers-color-scheme: dark) { #source p input ~ .r label.ctx:hover { color: #aaa; } }
+
+#source p input:checked ~ .r label.ctx { background: #d0e8ff; color: #666; border-radius: .75em .75em 0 0; padding: 0 .5em; margin: -.25em 0; }
+
+@media (prefers-color-scheme: dark) { #source p input:checked ~ .r label.ctx { background: #056; } }
+
+@media (prefers-color-scheme: dark) { #source p input:checked ~ .r label.ctx { color: #aaa; } }
+
+#source p input:checked ~ .r label.ctx::before { content: "▼ "; }
+
+#source p input:checked ~ .ctxs { padding: .25em .5em; overflow-y: scroll; max-height: 10.5em; }
+
+#source p label.ctx { color: #999; display: inline-block; padding: 0 .5em; font-size: .8333em; }
+
+@media (prefers-color-scheme: dark) { #source p label.ctx { color: #777; } }
+
+#source p .ctxs { display: block; max-height: 0; overflow-y: hidden; transition: all .2s; padding: 0 .5em; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; white-space: nowrap; background: #d0e8ff; border-radius: .25em; margin-right: 1.75em; text-align: right; }
+
+@media (prefers-color-scheme: dark) { #source p .ctxs { background: #056; } }
+
+#index { font-family: SFMono-Regular, Menlo, Monaco, Consolas, monospace; font-size: 0.875em; }
+
+#index table.index { margin-left: -.5em; }
+
+#index td, #index th { text-align: right; padding: .25em .5em; border-bottom: 1px solid #eee; }
+
+@media (prefers-color-scheme: dark) { #index td, #index th { border-color: #333; } }
+
+#index td.name, #index th.name { text-align: left; width: auto; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; min-width: 15em; }
+
+#index th { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; font-style: italic; color: #333; cursor: pointer; }
+
+@media (prefers-color-scheme: dark) { #index th { color: #ddd; } }
+
+#index th:hover { background: #eee; }
+
+@media (prefers-color-scheme: dark) { #index th:hover { background: #333; } }
+
+#index th .arrows { color: #666; font-size: 85%; font-family: sans-serif; font-style: normal; pointer-events: none; }
+
+#index th[aria-sort="ascending"], #index th[aria-sort="descending"] { white-space: nowrap; background: #eee; padding-left: .5em; }
+
+@media (prefers-color-scheme: dark) { #index th[aria-sort="ascending"], #index th[aria-sort="descending"] { background: #333; } }
+
+#index th[aria-sort="ascending"] .arrows::after { content: " ▲"; }
+
+#index th[aria-sort="descending"] .arrows::after { content: " ▼"; }
+
+#index td.name { font-size: 1.15em; }
+
+#index td.name a { text-decoration: none; color: inherit; }
+
+#index td.name .no-noun { font-style: italic; }
+
+#index tr.total td, #index tr.total_dynamic td { font-weight: bold; border-top: 1px solid #ccc; border-bottom: none; }
+
+#index tr.region:hover { background: #eee; }
+
+@media (prefers-color-scheme: dark) { #index tr.region:hover { background: #333; } }
+
+#index tr.region:hover td.name { text-decoration: underline; color: inherit; }
+
+#scroll_marker { position: fixed; z-index: 3; right: 0; top: 0; width: 16px; height: 100%; background: #fff; border-left: 1px solid #eee; will-change: transform; }
+
+@media (prefers-color-scheme: dark) { #scroll_marker { background: #1e1e1e; } }
+
+@media (prefers-color-scheme: dark) { #scroll_marker { border-color: #333; } }
+
+#scroll_marker .marker { background: #ccc; position: absolute; min-height: 3px; width: 100%; }
+
+@media (prefers-color-scheme: dark) { #scroll_marker .marker { background: #444; } }
diff --git a/coverage/z_0b97c06fcb6623f7___init___py.html b/coverage/z_0b97c06fcb6623f7___init___py.html
new file mode 100644
index 0000000..319957f
--- /dev/null
+++ b/coverage/z_0b97c06fcb6623f7___init___py.html
@@ -0,0 +1,288 @@
+
+
+
+
+
Coverage for pyEDAA/Launcher/__init__.py: 41%
+
+
+
+
+
+
+
+ 1 # ==================================================================================================================== #
+ 2 # _____ ____ _ _ _ _ #
+ 3 # _ __ _ _| ____| _ \ / \ / \ | | __ _ _ _ _ __ ___| |__ ___ _ __ #
+ 4 # | '_ \| | | | _| | | | |/ _ \ / _ \ | | / _` | | | | '_ \ / __| '_ \ / _ \ '__| #
+ 5 # | |_) | |_| | |___| |_| / ___ \ / ___ \ _| |__| (_| | |_| | | | | (__| | | | __/ | #
+ 6 # | .__/ \__, |_____|____/_/ \_\/_/ \_(_)_____\__,_|\__,_|_| |_|\___|_| |_|\___|_| #
+ 7 # |_| |___/ #
+ 8 # ==================================================================================================================== #
+ 9 # Authors: #
+ 10 # Stefan Unrein #
+ 11 # Patrick Lehmann #
+ 12 # #
+ 13 # License: #
+ 14 # ==================================================================================================================== #
+ 15 # Copyright 2021-2024 Stefan Unrein - Endingen, Germany #
+ 16 # #
+ 17 # Licensed under the Apache License, Version 2.0 (the "License"); #
+ 18 # you may not use this file except in compliance with the License. #
+ 19 # You may obtain a copy of the License at #
+ 20 # #
+ 21 # http://www.apache.org/licenses/LICENSE-2.0 #
+ 22 # #
+ 23 # Unless required by applicable law or agreed to in writing, software #
+ 24 # distributed under the License is distributed on an "AS IS" BASIS, #
+ 25 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. #
+ 26 # See the License for the specific language governing permissions and #
+ 27 # limitations under the License. #
+ 28 # #
+ 29 # SPDX-License-Identifier: Apache-2.0 #
+ 30 # ==================================================================================================================== #
+ 31 #
+ 32 """Start the correct Vivado Version based on version in `*.xpr`file."""
+ 33 __author__ = "Stefan Unrein"
+ 34 __email__ = "stefan.unrein@gmx.net"
+ 35 __copyright__ = "2021-2024, Stefan Unrein"
+ 36 __license__ = "Apache License, Version 2.0"
+ 37 __version__ = "0.1.0"
+ 38 __keywords__ = [ "launcher" , "version selector" , "xilinx" , "vivado" ]
+ 39
+ 40 from re import compile as re_compile
+ 41
+ 42 from sys import exit , argv
+ 43 import subprocess
+ 44 from pathlib import Path
+ 45 from textwrap import dedent
+ 46 from time import sleep
+ 47 from typing import NoReturn , Generator
+ 48
+ 49 from pyTooling . Decorators import export
+ 50
+ 51
+ 52 @ export
+ 53 class Program :
+ 54 """Program instance of pyEDAA.Launcher."""
+ 55
+ 56 vivadoBatchfile = Path ( "bin/vivado.bat" )
+ 57 vvglWrapperFile = Path ( "bin/unwrapped/win64.o/vvgl.exe" )
+ 58
+ 59 versionLineRegExp = re_compile ( r"^<!--\s*Product\sVersion:\s+Vivado\s+v(?P<major>\d+).(?P<minor>\d+)(?:.(?P<patch>\d+))?\s+\(64-bit\)\s+-->" )
+ 60
+ 61 _projectFilePath : Path
+ 62
+ 63
+ 64 def __init__ ( self , projectFilePath : Path ) -> None :
+ 65 """Initializer.
+ 66
+ 67 :param projectFilePath: Path to the ``*.xpr`` file.
+ 68 :raises Exception: When the given ``*.xpr`` file doesn't exist.
+ 69 """
+ 70 if not projectFilePath . exists ( ) : 70 ↛ 71 line 70 didn't jump to line 71 because the condition on line 70 was never true
+ 71 raise Exception ( f" Vivado project file ' { projectFilePath } ' not found. " ) \
+ 72 from FileNotFoundError ( f" File ' { projectFilePath } ' not found. " )
+ 73
+ 74 self . _projectFilePath = projectFilePath
+ 75
+ 76 def GetVersion ( self ) -> str :
+ 77 """Opens an ``*.xpr`` file and returns the Vivado version used to save this file.
+ 78
+ 79 :returns: Used Vivado version to save the given ``*.xpr`` file.
+ 80 :raises Exception: When the version information isn't found in the file.
+ 81 """
+ 82 with self . _projectFilePath . open ( "r" , encoding = "utf-8" ) as file :
+ 83 for line in file : 83 ↛ 88 line 83 didn't jump to line 88 because the loop on line 83 didn't complete
+ 84 match = self . versionLineRegExp . match ( line )
+ 85 if match is not None :
+ 86 return f" { match [ 'major' ] } . { match [ 'minor' ] } "
+ 87 else :
+ 88 raise Exception ( f" Pattern not found in ' { self . _projectFilePath } '. " )
+ 89
+ 90 @ classmethod
+ 91 def GetVivadoVersions ( self , installPath : Path ) -> Generator [ str , None , None ] :
+ 92 """Scan a given directory for installed Vivado versions.
+ 93
+ 94 :param installPath: Xilinx installation directory.
+ 95 :returns: A generator for a sequence of installed Vivado versions.
+ 96 """
+ 97 for item in installPath . iterdir ( ) :
+ 98 if item . is_dir ( ) :
+ 99 yield item . name
+ 100
+ 101 def StartVivado ( self , xilinxInstallationPath : Path , version : str ) -> NoReturn :
+ 102 """Start the given Vivado version with an ``*.xpr`` file as parameter.
+ 103
+ 104 :param xilinxInstallationPath: Path to the Xilinx toolchain installations.
+ 105 :param version: The Vivado version to start.
+ 106 """
+ 107 vivadoInstallationPath = xilinxInstallationPath / version
+ 108
+ 109 vvglWrapperPath = vivadoInstallationPath / self . vvglWrapperFile
+ 110 vivadoBatchfilePath = vivadoInstallationPath / self . vivadoBatchfile
+ 111
+ 112 cmd = [ str ( vvglWrapperPath ) , str ( vivadoBatchfilePath ) , str ( self . _projectFilePath ) ]
+ 113 subprocess . Popen ( cmd , cwd = self . _projectFilePath . parent ) # , creationflags=subprocess.DETACHED_PROCESS)
+ 114
+ 115 print ( "" )
+ 116 print ( f" Opening project with Vivado { version } . " )
+ 117
+ 118 sleep ( 2 )
+ 119 exit ( 0 )
+ 120
+ 121 @ classmethod
+ 122 def PrintHelp ( cls , scriptPath : Path ) -> None :
+ 123 """Print a help page.
+ 124
+ 125 :param scriptPath: Path to this script.
+ 126 """
+ 127 print ( dedent ( f""" \
+ 128 Run-Path ' { scriptPath } '
+ 129
+ 130 For using this Launcher, please bind the *.xpr file extension to this executable with:
+ 131 * Put this executable into the Vivado installation folder. E.g: C:\\Xilinx\\Vivado\\
+ 132 * Change *.xpr association: right-click -> open with -> VivadoManager.exe
+ 133 """ ) )
+ 134
+ 135
+ 136 @ export
+ 137 def main ( ) -> NoReturn :
+ 138 """Entry point function.
+ 139
+ 140 It creates an instance of :class:`Program` and hands over the execution to the OOP world.
+ 141 """
+ 142 xilinxInstallationPath = Path . cwd ( )
+ 143 scriptPath = Path ( argv [ 0 ] )
+ 144
+ 145 if ( argc := len ( argv ) ) == 0 :
+ 146 Program . PrintHelp ( scriptPath )
+ 147
+ 148 print ( f" Current path ' { xilinxInstallationPath } ' contains the following folders: " )
+ 149 for version in Program . GetVivadoVersions ( xilinxInstallationPath ) :
+ 150 print ( f" * { version } " )
+ 151
+ 152 print ( "" )
+ 153 print ( "Press any key to exit." )
+ 154
+ 155 # wait on user interaction
+ 156 input ( )
+ 157 exit ( 0 )
+ 158
+ 159 elif argc == 1 :
+ 160 projectFileArgument = argv [ 1 ]
+ 161 projectFilePath = Path ( projectFileArgument )
+ 162
+ 163 program = Program ( projectFilePath )
+ 164
+ 165 try :
+ 166 versionFromXPRFile = program . GetVersion ( )
+ 167 except Exception as ex :
+ 168 print ( f" [ERROR] { ex } " )
+ 169 exit ( 1 )
+ 170
+ 171 for version in program . GetVivadoVersions ( xilinxInstallationPath ) :
+ 172 if version == versionFromXPRFile :
+ 173 program . StartVivado ( xilinxInstallationPath , versionFromXPRFile )
+ 174 else :
+ 175 vivadoPath = xilinxInstallationPath / versionFromXPRFile
+ 176 print ( dedent ( f""" \
+ 177 ERROR: Vivado version { versionFromXPRFile } not available at path ' { vivadoPath } '. Please start manually!
+ 178
+ 179 Press any key to exit.
+ 180 """ ) )
+ 181
+ 182 # wait on user interaction
+ 183 input ( )
+ 184 exit ( 1 )
+ 185
+ 186
+ 187 # Entry point
+ 188 if __name__ == "__main__" : 188 ↛ 189 line 188 didn't jump to line 189 because the condition on line 188 was never true
+ 189 main ( )
+
+
+
+
diff --git a/genindex.html b/genindex.html
new file mode 100644
index 0000000..0c1c37d
--- /dev/null
+++ b/genindex.html
@@ -0,0 +1,238 @@
+
+
+
+
+
+
+
+
Index — pyEDAA.Launcher 0.1.0 documentation
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ pyEDAA.Launcher
+
+
+
+
+
+
+
+
+
+
Index
+
+
+
_
+ |
G
+ |
M
+ |
P
+ |
S
+ |
V
+ |
X
+
+
+
_
+
+
+
G
+
+
+
M
+
+
+
P
+
+
+
+
+ pyEDAA.Launcher
+
+
+
+
+
+
S
+
+
+
V
+
+
+
X
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/index.html b/index.html
new file mode 100644
index 0000000..fe630c5
--- /dev/null
+++ b/index.html
@@ -0,0 +1,219 @@
+
+
+
+
+
+
+
+
+
The pyEDAA.Launcher Documentation — pyEDAA.Launcher 0.1.0 documentation
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ pyEDAA.Launcher
+
+
+
+
+
+
+
+
+
+
+
+
+The pyEDAA.Launcher Documentation
+pyEDAA.Launcher starts the correct Xilinx Vivado version based on the version number written into the *.xpr
file.
+If no suitable version was found, an error message is shown.
+
+Main Goals
+When opening Xilinx Vivado by double-clicking an *.xpr
file in the Windows Explorer, a default Vivado version is
+launched by Windows. In many cases, this is the first Vivado version that was installed on a system, but not the latest
+version. Anyhow, in most cases, Windows starts the wrong Vivado version, which leeds to a project upgrade question, or a
+rejection, because the project file is too new.
+pyEDAA.Launcher addresses exactly this problem. It will start the correct Xilinx Vivado installation with correct
+working directory settings, if that requested Vivado version is found on the system.
+
+How does it work?
+
+Check with which Vivado version was used to save the *.xpr
file.
+Scan the Xilinx installation directory for available Vivado versions.
+If a matching version was found, start Vivado and pass the *.xpr
as a parameter.
+
+
+
+Differences to opening the *.xpr
from within Vivado GUI?
+By default, Xilinx Vivado has its working directory in AppData
, but the working directory should be in the directory
+where the *.xpr
file is located. This is fixed by pyEDAA.Launcher as a side effect. Now, Vivado saves log and
+journal files to the correct locations.
+
+
+
+News
+
+Feb. 2022 - Documentation und Unit Test Enhancements
+
+
+Updated documentation.
+Added simple unit tests.
+
+
+Dec. 2021 - Initial Prototype
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/objects.inv b/objects.inv
new file mode 100644
index 0000000..6254e52
Binary files /dev/null and b/objects.inv differ
diff --git a/py-modindex.html b/py-modindex.html
new file mode 100644
index 0000000..66d1454
--- /dev/null
+++ b/py-modindex.html
@@ -0,0 +1,167 @@
+
+
+
+
+
+
+
+
Python Module Index — pyEDAA.Launcher 0.1.0 documentation
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ pyEDAA.Launcher
+
+
+
+
+
+
+
+ Python Module Index
+
+
+
+
+
+
+
+
+
+
Python Module Index
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pyEDAA.Launcher/index.html b/pyEDAA.Launcher/index.html
new file mode 100644
index 0000000..bb23120
--- /dev/null
+++ b/pyEDAA.Launcher/index.html
@@ -0,0 +1,164 @@
+
+
+
+
+
+
+
+
+
Python Class Reference — pyEDAA.Launcher 0.1.0 documentation
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ pyEDAA.Launcher
+
+
+
+
+
+
+
+
+
+Python Class Reference
+Reference of all packages and modules:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pyEDAA.Launcher/pyEDAA.Launcher.html b/pyEDAA.Launcher/pyEDAA.Launcher.html
new file mode 100644
index 0000000..d9c3a53
--- /dev/null
+++ b/pyEDAA.Launcher/pyEDAA.Launcher.html
@@ -0,0 +1,286 @@
+
+
+
+
+
+
+
+
+
pyEDAA.Launcher — pyEDAA.Launcher 0.1.0 documentation
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ pyEDAA.Launcher
+
+
+
+
+
+
+
+
+
+pyEDAA.Launcher
+Start the correct Vivado Version based on version in ` * .xpr`file.
+Functions
+
+Classes
+
+
+Functions
+
+
+pyEDAA.Launcher. main ( ) [source]
+Entry point function.
+It creates an instance of Program
and hands over the execution to the OOP world.
+
+Return type:
+NoReturn
+
+
+
+
+
+Classes
+
+
+class pyEDAA.Launcher. Program ( projectFilePath ) [source]
+Program instance of pyEDAA.Launcher.
+Inheritance
+
+Inheritance diagram of Program
+
+Parameters:
+projectFilePath (Path )
+
+
+
+
+__init__ ( projectFilePath ) [source]
+Initializer.
+
+Parameters:
+projectFilePath (Path
) – Path to the *.xpr
file.
+
+Raises:
+Exception – When the given *.xpr
file doesn’t exist.
+
+Return type:
+None
+
+
+
+
+
+
+GetVersion ( ) [source]
+Opens an *.xpr
file and returns the Vivado version used to save this file.
+
+Return type:
+str
+
+Returns:
+Used Vivado version to save the given *.xpr
file.
+
+Raises:
+Exception – When the version information isn’t found in the file.
+
+
+
+
+
+
+classmethod GetVivadoVersions ( installPath ) [source]
+Scan a given directory for installed Vivado versions.
+
+Parameters:
+installPath (Path
) – Xilinx installation directory.
+
+Return type:
+Generator
[str
, None
, None
]
+
+Returns:
+A generator for a sequence of installed Vivado versions.
+
+
+
+
+
+
+StartVivado ( xilinxInstallationPath , version ) [source]
+Start the given Vivado version with an *.xpr
file as parameter.
+
+Parameters:
+
+
+Return type:
+NoReturn
+
+
+
+
+
+
+classmethod PrintHelp ( scriptPath ) [source]
+Print a help page.
+
+Parameters:
+scriptPath (Path
) – Path to this script.
+
+Return type:
+None
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/search.html b/search.html
new file mode 100644
index 0000000..0291682
--- /dev/null
+++ b/search.html
@@ -0,0 +1,162 @@
+
+
+
+
+
+
+
+
Search — pyEDAA.Launcher 0.1.0 documentation
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ pyEDAA.Launcher
+
+
+
+
+
+
+
+
+
+
+
+ Please activate JavaScript to enable the search functionality.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/searchindex.js b/searchindex.js
new file mode 100644
index 0000000..9b8e3fa
--- /dev/null
+++ b/searchindex.js
@@ -0,0 +1 @@
+Search.setIndex({"alltitles": {"1. Definitions.": [[5, "definitions"]], "2. Grant of Copyright License.": [[5, "grant-of-copyright-license"]], "3. Grant of Patent License.": [[5, "grant-of-patent-license"]], "4. Redistribution.": [[5, "redistribution"]], "5. Submission of Contributions.": [[5, "submission-of-contributions"]], "6. Trademarks.": [[5, "trademarks"]], "7. Disclaimer of Warranty.": [[5, "disclaimer-of-warranty"]], "8. Limitation of Liability.": [[5, "limitation-of-liability"]], "9. Accepting Warranty or Additional Liability.": [[5, "accepting-warranty-or-additional-liability"]], "Apache License 2.0": [[5, null]], "Building documentation": [[4, "building-documentation"]], "Code Coverage Report": [[8, null]], "Contributors": [[9, "contributors"]], "Creative Commons Attribution 4.0 International": [[1, null]], "Dec. 2021 - Initial Prototype": [[9, "dec-2021-initial-prototype"]], "Dependencies": [[0, null]], "Differences to opening the *.xpr from within Vivado GUI?": [[9, "differences-to-opening-the-xpr-from-within-vivado-gui"]], "Documentation Coverage": [[2, null]], "Feb. 2022 - Documentation und Unit Test Enhancements": [[9, "feb-2022-documentation-und-unit-test-enhancements"]], "Glossary": [[3, null]], "How does it work?": [[9, "how-does-it-work"]], "Installation/Updates": [[4, null]], "Installing a Wheel Package from PyPI using PIP": [[4, "installing-a-wheel-package-from-pypi-using-pip"]], "License": [[9, "license"]], "Local Packaging and Installation via PIP": [[4, "local-packaging-and-installation-via-pip"]], "Main Goals": [[9, "main-goals"]], "News": [[9, "news"]], "Packaging (Optional)": [[0, "packaging-optional"]], "Publishing (CI-Server only)": [[0, "publishing-ci-server-only"]], "Python Class Reference": [[10, null]], "Referencing the package in requirements.txt": [[4, "referencing-the-package-in-requirements-txt"]], "Running type checks": [[4, "running-type-checks"]], "Running unit tests": [[4, "running-unit-tests"]], "Section 1 \u2013 Definitions.": [[1, "section-1-definitions"]], "Section 2 \u2013 Scope.": [[1, "section-2-scope"]], "Section 3 \u2013 License Conditions.": [[1, "section-3-license-conditions"]], "Section 4 \u2013 Sui Generis Database Rights.": [[1, "section-4-sui-generis-database-rights"]], "Section 5 \u2013 Disclaimer of Warranties and Limitation of Liability.": [[1, "section-5-disclaimer-of-warranties-and-limitation-of-liability"]], "Section 6 \u2013 Term and Termination.": [[1, "section-6-term-and-termination"]], "Section 7 \u2013 Other Terms and Conditions.": [[1, "section-7-other-terms-and-conditions"]], "Section 8 \u2013 Interpretation.": [[1, "section-8-interpretation"]], "Sphinx Documentation (Optional)": [[0, "sphinx-documentation-optional"]], "Static Type Checking Report": [[12, null]], "TODOs": [[6, null]], "The pyEDAA.Launcher Documentation": [[9, null]], "Todo": [[4, "id1"], [4, "id2"], [6, null], [6, null], [6, null], [7, "id1"]], "Uninstallation using PIP": [[4, "uninstallation-using-pip"]], "Unit Testing (Optional)": [[0, "unit-testing-optional"]], "Unit Testing / Coverage / Type Checking (Optional)": [[0, "unit-testing-coverage-type-checking-optional"]], "Unittest Summary Report": [[13, null]], "Updating from PyPI using PIP": [[4, "updating-from-pypi-using-pip"]], "Usage": [[7, null]], "Using Creative Commons Public Licenses": [[1, null]], "Using PIP to Install from PyPI": [[4, "using-pip-to-install-from-pypi"]], "pyEDAA.Launcher": [[11, null]], "pyEDAA.Launcher Package (Mandatory)": [[0, "pyedaa-launcher-package-mandatory"]], "requirements.txt": [[4, null]]}, "docnames": ["Dependency", "Doc-License", "DocCoverage", "Glossary", "Installation", "License", "TODO", "Usage", "coverage/index", "index", "pyEDAA.Launcher/index", "pyEDAA.Launcher/pyEDAA.Launcher", "typing/index", "unittests/index"], "envversion": {"sphinx": 64, "sphinx.domains.c": 3, "sphinx.domains.changeset": 1, "sphinx.domains.citation": 1, "sphinx.domains.cpp": 9, "sphinx.domains.index": 1, "sphinx.domains.javascript": 3, "sphinx.domains.math": 2, "sphinx.domains.python": 4, "sphinx.domains.rst": 2, "sphinx.domains.std": 2, "sphinx.ext.intersphinx": 1, "sphinx.ext.todo": 2, "sphinx.ext.viewcode": 1}, "filenames": ["Dependency.rst", "Doc-License.rst", "DocCoverage.rst", "Glossary.rst", "Installation.rst", "License.rst", "TODO.rst", "Usage.rst", "coverage/index.rst", "index.rst", "pyEDAA.Launcher/index.rst", "pyEDAA.Launcher/pyEDAA.Launcher.rst", "typing/index.rst", "unittests/index.rst"], "indexentries": {"__init__() (pyedaa.launcher.program method)": [[11, "pyEDAA.Launcher.Program.__init__", false]], "getversion() (pyedaa.launcher.program method)": [[11, "pyEDAA.Launcher.Program.GetVersion", false]], "getvivadoversions() (pyedaa.launcher.program class method)": [[11, "pyEDAA.Launcher.Program.GetVivadoVersions", false]], "main() (in module pyedaa.launcher)": [[11, "pyEDAA.Launcher.main", false]], "module": [[11, "module-pyEDAA.Launcher", false]], "printhelp() (pyedaa.launcher.program class method)": [[11, "pyEDAA.Launcher.Program.PrintHelp", false]], "program (class in pyedaa.launcher)": [[11, "pyEDAA.Launcher.Program", false]], "pyedaa.launcher": [[11, "module-pyEDAA.Launcher", false]], "startvivado() (pyedaa.launcher.program method)": [[11, "pyEDAA.Launcher.Program.StartVivado", false]], "vivado": [[3, "term-Vivado", true]], "xml": [[3, "term-XML", true]], "xpr file": [[3, "term-XPR-file", true]]}, "objects": {"pyEDAA": [[11, 0, 0, "-", "Launcher"]], "pyEDAA.Launcher": [[11, 1, 1, "", "Program"], [11, 3, 1, "", "main"]], "pyEDAA.Launcher.Program": [[11, 2, 1, "", "GetVersion"], [11, 2, 1, "", "GetVivadoVersions"], [11, 2, 1, "", "PrintHelp"], [11, 2, 1, "", "StartVivado"], [11, 2, 1, "", "__init__"]]}, "objnames": {"0": ["py", "module", "Python module"], "1": ["py", "class", "Python class"], "2": ["py", "method", "Python method"], "3": ["py", "function", "Python function"]}, "objtypes": {"0": "py:module", "1": "py:class", "2": "py:method", "3": "py:function"}, "terms": {"": [1, 4, 5], "0": [0, 2, 4, 8, 9, 13], "00": 13, "002": 13, "1": [0, 2, 4, 8, 13], "100": [2, 8], "11": 1, "12": 0, "13": 0, "17": 8, "18": 0, "1996": 1, "2": [0, 8, 9], "20": 1, "2004": 5, "218": 13, "22": 8, "3": [0, 4, 8], "30": 1, "37": 8, "4": [0, 9], "41": 8, "43": 8, "45": 0, "5": [0, 8], "50": 5, "6": 0, "7": 0, "8": [0, 2], "80": 8, "9": 1, "96": 1, "A": [1, 4, 5, 11], "AND": 5, "AS": 5, "As": 4, "BY": [1, 9], "By": [1, 9], "FOR": 5, "For": [1, 4, 5], "If": [1, 5, 9], "In": [1, 4, 5, 9], "It": [4, 9, 11], "No": 1, "Not": [0, 5], "OF": 5, "OR": 5, "The": [0, 1, 4, 5, 11], "These": [0, 4], "To": [1, 5], "With": 4, "_": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13], "__init__": [10, 11], "_build": 4, "abov": [1, 5], "absenc": 1, "absolut": 1, "accept": 1, "access": 1, "accompani": 9, "accord": 1, "accuraci": 1, "act": 5, "ad": [4, 9], "adapt": 1, "add": 5, "addendum": 5, "addit": [0, 1, 4], "address": 9, "adopt": 1, "advic": 1, "advis": [1, 5], "affect": 1, "against": 5, "agre": [1, 5], "agreement": [1, 5], "all": [0, 1, 4, 5, 10], "alleg": 5, "allow": 1, "alon": 5, "along": 5, "alongsid": 5, "also": [1, 4, 5], "alter": 1, "altern": 4, "although": 1, "alwai": 1, "amd": 3, "amend": 1, "an": [1, 4, 5, 9, 11], "ani": [0, 1, 4, 5], "annot": 5, "anoth": 4, "ant": 4, "anyhow": 9, "anymor": 4, "anywher": 1, "apach": [0, 9], "appdata": 9, "appear": 5, "appendix": 5, "appli": [1, 5], "applic": [1, 5], "appropri": [4, 5], "approxim": 1, "ar": [0, 1, 4, 5], "archiv": 5, "argcomplet": 0, "aris": [1, 5], "arrang": 1, "articl": 1, "artifact": 4, "artist": 1, "ask": 1, "assert": [1, 5, 13], "associ": 5, "assum": 5, "attach": 5, "attribut": [5, 9], "author": [1, 5, 9], "authorship": [1, 5], "autoapi": 0, "automat": 1, "avail": [1, 5, 9], "avoid": 1, "b": [1, 4], "base": [1, 3, 5, 9, 11], "basi": [1, 5], "basic": 4, "bat": 4, "bdist_wheel": 4, "becaus": [1, 9], "been": [1, 5], "befor": 1, "behalf": 5, "below": [1, 5], "benefici": 5, "benefit": 1, "bind": 5, "bitstream": 3, "boilerpl": 5, "bound": 1, "bracket": 5, "branch": [4, 8], "broadcast": 1, "bsd": 0, "bug": 4, "build": 0, "can": [1, 4], "cannot": [1, 5], "carri": 5, "case": [1, 4, 9], "categor": 1, "caus": 5, "cc": [1, 9], "cd": 4, "certain": 1, "chang": [1, 5], "charact": 5, "charg": 5, "check": 9, "choos": [1, 5], "chosen": 1, "circumv": 1, "claim": 5, "class": [5, 11], "classmethod": 11, "claus": 0, "clearli": 1, "click": 9, "client": 1, "clitool": 0, "close": 1, "cobertura": 4, "code": [0, 4, 5, 9], "collect": [0, 1, 4], "color": 4, "combin": 5, "comment": 5, "commerci": 5, "common": [4, 5, 9], "commun": [1, 5], "compil": 5, "compli": [1, 5], "complianc": 5, "compulsori": 1, "comput": 5, "concern": 1, "condit": 5, "configur": 5, "connect": 1, "consent": 1, "consequenti": [1, 5], "consid": 1, "consider": 1, "consist": 5, "consol": 4, "conspicu": 5, "constitut": [1, 5], "constru": [1, 5], "contact": 1, "contain": 5, "content": [1, 4, 5], "context": 1, "contract": [1, 5], "contribut": 1, "contributor": 5, "contributori": 5, "control": 5, "convers": [4, 5, 6], "convert": 4, "copi": [1, 5], "copybutton": 0, "copyright": 1, "corpor": 1, "corral": 9, "correct": [9, 11], "correspond": 1, "cost": 1, "could": 1, "council": 1, "counterclaim": 5, "cov": 0, "cover": [2, 8], "coverag": 4, "creat": [1, 4, 11], "creativ": 9, "creativecommon": 1, "creator": 1, "cross": 5, "cure": 1, "customari": 5, "d": 4, "dai": 1, "damag": [1, 5], "data": 4, "date": [1, 5], "deal": 1, "decemb": 1, "deem": 1, "default": 9, "defect": 1, "defend": 5, "defin": [1, 5], "deliber": 5, "depend": 4, "deriv": [1, 5], "describ": [1, 4, 5, 6], "descript": 5, "design": [1, 5], "detail": 4, "detect": 4, "determin": 5, "develop": [0, 4, 9], "differ": [1, 5], "direct": [1, 5], "directli": [0, 1], "directori": [4, 9, 11], "discover": 1, "discoveri": 1, "discuss": 5, "displai": [1, 5], "dissemin": 1, "dist": [0, 4], "distribut": [1, 5], "do": [1, 5], "doc": [0, 4], "docstr": 2, "doctre": 4, "document": [1, 5, 6, 7], "doe": [1, 5], "doesn": 11, "don": 5, "doubl": 9, "doubt": 1, "download": 4, "downstream": 1, "e": 0, "each": 5, "easier": 5, "ec": 1, "editori": 5, "effect": [1, 9], "either": 5, "elabor": 5, "elect": 1, "electron": 5, "enclos": 5, "encourag": 1, "endors": 1, "enforc": 1, "ensur": 4, "entiti": [1, 5], "entri": [6, 11], "env": 4, "environ": 4, "equival": [0, 1], "error": [1, 9, 13], "essenti": 1, "european": 1, "evalu": 0, "even": [1, 5], "event": [1, 5], "everi": 1, "exactli": 9, "exampl": [1, 5], "except": [1, 5, 11], "exclud": [5, 8], "exclus": [1, 5], "execut": [4, 5, 11], "exemplari": 1, "exercis": [1, 5], "exhaust": 1, "exist": 11, "expect": 1, "expens": 1, "explicitli": 5, "explor": 9, "export": 4, "express": [1, 5], "expressli": 1, "extens": [0, 3], "extent": 1, "extract": 1, "fail": [1, 13], "failur": [1, 5], "fair": 1, "fee": 5, "field": 5, "fifti": 5, "file": [0, 2, 3, 4, 5, 8, 9, 11], "filenam": 2, "firm": 1, "first": 9, "fit": [1, 5], "fix": [4, 9], "follow": [1, 4, 5], "forbid": 1, "form": [1, 5], "format": [1, 5], "found": [9, 11], "fpga": 3, "free": [1, 5], "from": [0, 1, 5], "fulfil": 1, "full": 1, "fullest": 1, "function": 11, "further": [0, 4], "g": 0, "gener": [0, 2, 3, 4, 5, 8, 11, 12, 13], "getvers": [10, 11], "getvivadovers": [10, 11], "give": [1, 5], "given": 11, "goodwil": 5, "govern": 5, "grant": 1, "grossli": 5, "ha": [1, 5, 9], "hand": 11, "handi": 4, "harmless": 5, "have": [1, 4, 5], "held": 1, "help": 11, "here": 1, "hereaft": 1, "herebi": [1, 5], "herein": [1, 5], "hh": 13, "hold": 5, "holder": 1, "how": [1, 4, 5], "howev": [1, 5], "html": 4, "html1": 4, "http": 5, "hyperlink": 1, "i": [1, 3, 4, 5, 9], "identif": [1, 5], "identifi": 5, "ii": 5, "iii": 5, "imag": 1, "immun": 1, "impli": [1, 5], "import": [1, 5], "impos": 1, "improv": 5, "inabl": 5, "incident": [1, 5], "includ": [1, 4, 5], "inclus": 5, "incorpor": 5, "incur": 5, "indemn": 5, "indemnifi": 5, "independ": 1, "index": 4, "indic": [1, 5], "indirect": [1, 5], "individu": [1, 5], "inform": [1, 5, 11], "infring": [1, 5], "inherit": 11, "initi": 11, "instal": [0, 9, 11], "installpath": 11, "instanc": [1, 11], "institut": 5, "instruct": 4, "integr": 1, "intend": 1, "intention": 5, "interfac": 5, "io": 0, "irrevoc": [1, 5], "isn": 11, "issu": 5, "its": [1, 5, 9], "itself": 4, "j": 4, "januari": 5, "journal": 9, "junit": 4, "junitxml": 4, "jurisdict": 1, "just": 4, "kind": [1, 5], "known": 1, "label": 1, "languag": [3, 5], "latent": 1, "latest": 9, "latex": [4, 6], "launch": 9, "launcher": [2, 4, 8, 10], "law": [1, 5], "lawfulli": 1, "lawsuit": 5, "lawyer": 1, "least": 5, "leed": 9, "legaci": 4, "legal": [1, 5], "lehmann": 9, "liabl": [1, 5], "librari": 0, "licens": 0, "licensor": [1, 5], "like": 4, "line": 4, "link": 5, "linux": [0, 4, 6], "list": [0, 4, 5], "literari": 1, "litig": 5, "local": [1, 5], "locat": 9, "log": [4, 9], "logo": 1, "loss": [1, 5], "lxml": 0, "m": 4, "machin": 4, "maco": [0, 4], "made": [1, 5], "mai": [1, 5], "mail": 5, "main": [10, 11], "maintain": [0, 9], "make": [1, 4, 5], "malfunct": 5, "manag": [4, 5], "mani": 9, "manner": 1, "manual": 0, "march": 1, "mark": [1, 5], "markup": 3, "martinez": 9, "match": 9, "materi": 1, "mean": [1, 5], "measur": 1, "mechan": 5, "media": [1, 5], "medium": [1, 5], "meet": 5, "member": 1, "merchant": [1, 5], "mere": 5, "mermaid": 0, "messag": 9, "might": 4, "miktex": [4, 6], "minim": 4, "minimum": 1, "miss": [2, 8], "mit": 0, "mm": 13, "modif": [1, 5], "modifi": [1, 5], "modul": [8, 10], "moral": 1, "more": [1, 4, 5, 9], "most": [1, 9], "move": 1, "music": 1, "must": [1, 5], "mypi": [0, 4, 12], "mypy_force_color": 4, "n": 4, "name": 5, "necessari": [1, 4], "necessarili": 5, "need": [0, 1, 4, 6, 7], "neglig": [1, 5], "never": 1, "new": 4, "non": [1, 5], "none": [0, 4, 11], "nor": 1, "noreturn": 11, "normal": 5, "noth": [1, 5], "notic": [1, 5], "notwithstand": [1, 5], "now": [1, 3, 9], "nproc": 4, "number": [4, 9], "object": 5, "oblig": [1, 5], "obtain": 5, "offer": [1, 5], "offici": 1, "old": 4, "one": [1, 5], "onli": [1, 5], "oop": 11, "open": 11, "org": [1, 5], "origin": [1, 5, 6], "other": 5, "otherwis": [1, 5], "our": 1, "out": [1, 5], "output": 4, "outstand": 5, "over": 11, "overal": [2, 8], "overwrit": 4, "own": 5, "owner": 5, "ownership": 5, "p": 4, "packag": [8, 9, 10], "page": [5, 11], "paragraph": 1, "paramet": [9, 11], "parliament": 1, "part": [1, 5], "parti": [1, 5], "partial": 8, "particular": [1, 5], "pass": [9, 13], "patent": 1, "path": 11, "patrick": 9, "pdf": [4, 6], "percent": 5, "perform": [1, 5], "permiss": [1, 5], "permit": 1, "perpetu": 5, "person": 1, "pertain": 5, "pip": 0, "pip3": [0, 4], "place": [1, 5], "placehold": 12, "point": 11, "polici": 1, "portion": 1, "possibl": [1, 5], "power": 5, "practic": 1, "prefer": 5, "prepar": 5, "presenc": 1, "prevent": 1, "previou": [1, 4], "print": [5, 11], "printhelp": [10, 11], "prior": 1, "privaci": 1, "privileg": 1, "problem": 9, "process": 1, "produc": 1, "product": 5, "program": [10, 11], "project": [1, 3, 5, 9], "projectfilepath": 11, "promin": 5, "proper": 1, "protect": 1, "provid": [1, 3, 4, 5], "provis": 1, "pseudonym": 1, "psf": 0, "publicli": 5, "publish": 1, "punit": 1, "purpos": [1, 4, 5], "pwd": 4, "py": [4, 8], "py3": 4, "pyedaa": [2, 4, 8, 10], "pypi": 0, "pyproject": 4, "pytest": [0, 4, 8, 13], "python": [0, 4, 9], "python3": 4, "pythonpath": 4, "pytool": 0, "pyvhdlmodel": 0, "question": 9, "r": 0, "ra": 4, "rais": 11, "rap": 4, "rcfile": 4, "read": [1, 9], "readabl": 5, "readxprfil": 13, "reason": [1, 5], "receiv": [1, 5], "recipi": [1, 5], "recommend": [4, 5], "record": 1, "recurs": 0, "reduc": 1, "refer": 1, "reform": 1, "regard": [1, 5], "regul": 1, "reinstal": 4, "reinstat": 1, "reject": 9, "relat": 1, "relationship": 1, "remain": [1, 5], "remedi": 1, "remov": 1, "replac": [1, 5], "report": 4, "repres": 5, "represent": 1, "reproduc": [1, 5], "reproduct": [1, 5], "request": [1, 9], "requir": [0, 1, 5], "reserv": 1, "resourc": 1, "respect": 1, "respons": 5, "restrict": 1, "result": [1, 5], "retain": [1, 5], "return": 11, "reus": 1, "revis": 5, "right": 5, "risk": 5, "root": 4, "royalti": [1, 5], "ruamel": 0, "runtim": 13, "same": [4, 5], "satisfi": 1, "save": [9, 11], "scan": [9, 11], "scheme": 1, "script": [9, 11], "scriptpath": 11, "section": [4, 5], "secur": 1, "see": [0, 4, 5], "seek": 1, "sell": 5, "sent": 5, "separ": [1, 5], "sequenc": 11, "servic": [0, 1, 5], "set": [1, 9], "setup": 4, "sever": 1, "shall": [1, 5], "share": [1, 5], "should": [1, 5, 9], "shown": 9, "side": 9, "similar": 1, "simpl": 9, "simpli": 1, "skip": 13, "so": 1, "societi": 1, "softwar": 5, "sole": 5, "sound": 1, "sourc": [4, 5, 9, 11], "special": [1, 5], "specif": 5, "specifi": [1, 4], "sphinx": 4, "sphinx_autodoc_typehint": 0, "sphinx_btd_them": 0, "sphinx_design": 0, "sphinxcontrib": 0, "split": 4, "sponsor": 1, "ss": 13, "sss": 13, "standard": 1, "start": [9, 11], "startvivado": [10, 11], "state": [1, 5], "statement": 5, "static": 0, "statment": 8, "statu": 1, "statutori": 1, "stefan": 9, "step": 4, "still": 1, "stop": 1, "stoppag": 5, "str": 11, "sub": 0, "subject": [1, 5], "sublicens": [1, 5], "submit": 5, "subsequ": 5, "substanti": 1, "succeed": 1, "suitabl": 9, "summari": 0, "supersed": 5, "supplement": 1, "suppli": 1, "support": 5, "surviv": 1, "synch": 1, "syntax": 5, "system": [5, 9], "t": [5, 11], "tb": 4, "technic": 1, "technolog": 1, "templat": 4, "term": 5, "termin": 5, "test": 13, "test_extractversionfromxprfil": 13, "testcas": [4, 13], "testsuit": 13, "text": [1, 5], "than": 1, "thei": 1, "them": 1, "theori": [1, 5], "thereof": 5, "thi": [1, 4, 5, 9, 11], "third": 5, "those": [1, 5], "through": [1, 5], "thu": [0, 4], "time": 1, "titl": [1, 5], "toml": 4, "too": [0, 9], "toolchain": [3, 11], "tort": 5, "total": [2, 8], "track": 5, "trade": 5, "trademark": 1, "transfer": 5, "transform": [1, 5], "translat": [1, 4, 5], "treati": 1, "twine": 0, "txt": 0, "type": [5, 11], "u": [0, 4], "unai": 9, "unauthor": 1, "under": [1, 5, 9], "understand": 1, "undertaken": 1, "unenforc": 1, "union": 5, "unit": 13, "unittest": 4, "unless": [1, 5], "unrein": 9, "updat": [0, 9], "upgrad": 9, "upon": 1, "uri": 1, "us": [0, 5, 6, 9, 11], "user": 4, "v": 4, "verbal": 5, "verbos": 4, "version": [0, 4, 5, 9, 11], "via": 0, "violat": 1, "vivado": [3, 11, 13], "voluntari": 1, "vulner": 0, "w": 4, "wa": [5, 9], "wai": [1, 4], "waiv": 1, "waivabl": 1, "waiver": 1, "we": 5, "well": 1, "wheel": 0, "when": [4, 9, 11], "where": [1, 5, 9], "wherev": 5, "whether": [1, 5], "which": [1, 5, 9], "while": 5, "whl": 4, "whole": [1, 5], "whom": 5, "window": [0, 4, 6, 9], "wipo": 1, "within": [1, 5], "without": [1, 5], "work": [1, 5], "world": [1, 11], "worldwid": [1, 5], "write": [4, 5], "written": [1, 5, 9], "wrong": 9, "www": 5, "xilinx": [3, 9, 11], "xilinxinstallationpath": 11, "xml": [3, 4], "xpr": [3, 11], "y": 4, "yaml": 0, "ye": 4, "yet": 0, "you": [1, 5], "your": [1, 5], "yyyi": 5, "\u00aa": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13], "\u00b2": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13], "\u00b3": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13], "\u00b5": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13], "\u00b9": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13], "\u00ba": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13], "\u00bc": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13], "\u00bd": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13], "\u00be": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13], "\u02c7": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13], "\u03b5": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13], "\u03c2": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13], "\u03c5": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13], "\u03c6": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13], "\u03c9": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13], "\u03d1": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13], "\u03d5": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13], "\u03d6": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13], "\u03dd": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13], "\u03f0": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13], "\u03f1": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13], "\u03f5": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13], "\u2102": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13], "\u210b": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13], "\u210c": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13], "\u210d": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13], "\u210f": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13], "\u2110": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13], "\u2111": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13], "\u2112": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13], "\u2115": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13], "\u2119": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13], "\u211a": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13], "\u211b": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13], "\u211c": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13], "\u211d": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13], "\u2124": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13], "\u2128": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13], "\u212c": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13], "\u212d": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13], "\u2130": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13], "\u2131": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13], "\u2133": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13], "\u2134": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13], "\u2145": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13], "\u2146": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13], "\u2147": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13], "\u2148": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13], "\u215b": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13], "\u215c": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13], "\u215d": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13], "\u215e": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]}, "titles": ["Dependencies", "Creative Commons Attribution 4.0 International", "Documentation Coverage", "Glossary", "Installation/Updates", "Apache License 2.0", "TODOs", "Usage", "Code Coverage Report", "The pyEDAA.Launcher Documentation", "Python Class Reference", "pyEDAA.Launcher", "Static Type Checking Report", "Unittest Summary Report"], "titleterms": {"0": [1, 5], "1": [1, 5], "2": [1, 5], "2021": 9, "2022": 9, "3": [1, 5], "4": [1, 5], "5": [1, 5], "6": [1, 5], "7": [1, 5], "8": [1, 5], "9": 5, "The": 9, "accept": 5, "addit": 5, "apach": 5, "attribut": 1, "build": 4, "check": [0, 4, 12], "ci": 0, "class": 10, "code": 8, "common": 1, "condit": 1, "contribut": 5, "contributor": 9, "copyright": 5, "coverag": [0, 2, 8], "creativ": 1, "databas": 1, "dec": 9, "definit": [1, 5], "depend": 0, "differ": 9, "disclaim": [1, 5], "document": [0, 2, 4, 9], "doe": 9, "enhanc": 9, "feb": 9, "from": [4, 9], "generi": 1, "glossari": 3, "goal": 9, "grant": 5, "gui": 9, "how": 9, "initi": 9, "instal": 4, "intern": 1, "interpret": 1, "launcher": [0, 9, 11], "liabil": [1, 5], "licens": [1, 5, 9], "limit": [1, 5], "local": 4, "main": 9, "mandatori": 0, "new": 9, "onli": 0, "open": 9, "option": 0, "other": 1, "packag": [0, 4], "patent": 5, "pip": 4, "prototyp": 9, "public": 1, "publish": 0, "pyedaa": [0, 9, 11], "pypi": 4, "python": 10, "redistribut": 5, "refer": 10, "referenc": 4, "report": [8, 12, 13], "requir": 4, "right": 1, "run": 4, "scope": 1, "section": 1, "server": 0, "sphinx": 0, "static": 12, "submiss": 5, "sui": 1, "summari": 13, "term": 1, "termin": 1, "test": [0, 4, 9], "todo": [4, 6, 7], "trademark": 5, "txt": 4, "type": [0, 4, 12], "und": 9, "uninstal": 4, "unit": [0, 4, 9], "unittest": 13, "updat": 4, "us": [1, 4], "usag": 7, "via": 4, "vivado": 9, "warranti": [1, 5], "wheel": 4, "within": 9, "work": 9, "xpr": 9}})
\ No newline at end of file
diff --git a/typing/html/pyEDAA/Launcher/__init__.py.html b/typing/html/pyEDAA/Launcher/__init__.py.html
new file mode 100644
index 0000000..2b59644
--- /dev/null
+++ b/typing/html/pyEDAA/Launcher/__init__.py.html
@@ -0,0 +1,400 @@
+
+
+
+
+
+
+
pyEDAA.Launcher
+
+pyEDAA/Launcher/__init__.py
+
+1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+
+# ==================================================================================================================== #
+# _____ ____ _ _ _ _ #
+# _ __ _ _| ____| _ \ / \ / \ | | __ _ _ _ _ __ ___| |__ ___ _ __ #
+# | '_ \| | | | _| | | | |/ _ \ / _ \ | | / _` | | | | '_ \ / __| '_ \ / _ \ '__| #
+# | |_) | |_| | |___| |_| / ___ \ / ___ \ _| |__| (_| | |_| | | | | (__| | | | __/ | #
+# | .__/ \__, |_____|____/_/ \_\/_/ \_(_)_____\__,_|\__,_|_| |_|\___|_| |_|\___|_| #
+# |_| |___/ #
+# ==================================================================================================================== #
+# Authors: #
+# Stefan Unrein #
+# Patrick Lehmann #
+# #
+# License: #
+# ==================================================================================================================== #
+# Copyright 2021-2024 Stefan Unrein - Endingen, Germany #
+# #
+# Licensed under the Apache License, Version 2.0 (the "License"); #
+# you may not use this file except in compliance with the License. #
+# You may obtain a copy of the License at #
+# #
+# http://www.apache.org/licenses/LICENSE-2.0 #
+# #
+# Unless required by applicable law or agreed to in writing, software #
+# distributed under the License is distributed on an "AS IS" BASIS, #
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. #
+# See the License for the specific language governing permissions and #
+# limitations under the License. #
+# #
+# SPDX-License-Identifier: Apache-2.0 #
+# ==================================================================================================================== #
+#
+"""Start the correct Vivado Version based on version in `*.xpr`file."""
+__author__ = "Stefan Unrein"
+__email__ = "stefan.unrein@gmx.net"
+__copyright__ = "2021-2024, Stefan Unrein"
+__license__ = "Apache License, Version 2.0"
+__version__ = "0.1.0"
+__keywords__ = ["launcher", "version selector", "xilinx", "vivado"]
+
+from re import compile as re_compile
+
+from sys import exit, argv
+import subprocess
+from pathlib import Path
+from textwrap import dedent
+from time import sleep
+from typing import NoReturn, Generator
+
+from pyTooling.Decorators import export
+
+
+@export
+class Program:
+ """Program instance of pyEDAA.Launcher."""
+
+ vivadoBatchfile = Path("bin/vivado.bat")
+ vvglWrapperFile = Path("bin/unwrapped/win64.o/vvgl.exe")
+
+ versionLineRegExp = re_compile(r"^<!--\s*Product\sVersion:\s+Vivado\s+v(?P<major>\d+).(?P<minor>\d+)(?:.(?P<patch>\d+))?\s+\(64-bit\)\s+-->")
+
+ _projectFilePath: Path
+
+
+ def __init__(self, projectFilePath: Path) -> None:
+ """Initializer.
+
+ :param projectFilePath: Path to the ``*.xpr`` file.
+ :raises Exception: When the given ``*.xpr`` file doesn't exist.
+ """
+ if not projectFilePath.exists():
+ raise Exception(f"Vivado project file '{projectFilePath}' not found.") \
+ from FileNotFoundError(f"File '{projectFilePath}' not found.")
+
+ self._projectFilePath = projectFilePath
+
+ def GetVersion(self) -> str:
+ """Opens an ``*.xpr`` file and returns the Vivado version used to save this file.
+
+ :returns: Used Vivado version to save the given ``*.xpr`` file.
+ :raises Exception: When the version information isn't found in the file.
+ """
+ with self._projectFilePath.open("r", encoding="utf-8") as file:
+ for line in file:
+ match = self.versionLineRegExp.match(line)
+ if match is not None:
+ return f"{match['major']}.{match['minor']}"
+ else:
+ raise Exception(f"Pattern not found in '{self._projectFilePath}'.")
+
+ @classmethod
+ def GetVivadoVersions(self, installPath: Path) -> Generator[str, None, None]:
+ """Scan a given directory for installed Vivado versions.
+
+ :param installPath: Xilinx installation directory.
+ :returns: A generator for a sequence of installed Vivado versions.
+ """
+ for item in installPath.iterdir():
+ if item.is_dir():
+ yield item.name
+
+ def StartVivado(self, xilinxInstallationPath: Path, version: str) -> NoReturn:
+ """Start the given Vivado version with an ``*.xpr`` file as parameter.
+
+ :param xilinxInstallationPath: Path to the Xilinx toolchain installations.
+ :param version: The Vivado version to start.
+ """
+ vivadoInstallationPath = xilinxInstallationPath / version
+
+ vvglWrapperPath = vivadoInstallationPath / self.vvglWrapperFile
+ vivadoBatchfilePath = vivadoInstallationPath / self.vivadoBatchfile
+
+ cmd = [str(vvglWrapperPath), str(vivadoBatchfilePath), str(self._projectFilePath)]
+ subprocess.Popen(cmd, cwd=self._projectFilePath.parent) # , creationflags=subprocess.DETACHED_PROCESS)
+
+ print("")
+ print(f"Opening project with Vivado {version}.")
+
+ sleep(2)
+ exit(0)
+
+ @classmethod
+ def PrintHelp(cls, scriptPath: Path) -> None:
+ """Print a help page.
+
+ :param scriptPath: Path to this script.
+ """
+ print(dedent(f"""\
+ Run-Path '{scriptPath}'
+
+ For using this Launcher, please bind the *.xpr file extension to this executable with:
+ * Put this executable into the Vivado installation folder. E.g: C:\\Xilinx\\Vivado\\
+ * Change *.xpr association: right-click -> open with -> VivadoManager.exe
+ """))
+
+
+@export
+def main() -> NoReturn:
+ """Entry point function.
+
+ It creates an instance of :class:`Program` and hands over the execution to the OOP world.
+ """
+ xilinxInstallationPath = Path.cwd()
+ scriptPath = Path(argv[0])
+
+ if (argc := len(argv)) == 0:
+ Program.PrintHelp(scriptPath)
+
+ print(f"Current path '{xilinxInstallationPath}' contains the following folders:")
+ for version in Program.GetVivadoVersions(xilinxInstallationPath):
+ print(f"* {version}")
+
+ print("")
+ print("Press any key to exit.")
+
+ # wait on user interaction
+ input()
+ exit(0)
+
+ elif argc == 1:
+ projectFileArgument = argv[1]
+ projectFilePath = Path(projectFileArgument)
+
+ program = Program(projectFilePath)
+
+ try:
+ versionFromXPRFile = program.GetVersion()
+ except Exception as ex:
+ print(f"[ERROR] {ex}")
+ exit(1)
+
+ for version in program.GetVivadoVersions(xilinxInstallationPath):
+ if version == versionFromXPRFile:
+ program.StartVivado(xilinxInstallationPath, versionFromXPRFile)
+ else:
+ vivadoPath = xilinxInstallationPath / versionFromXPRFile
+ print(dedent(f"""\
+ ERROR: Vivado version {versionFromXPRFile} not available at path '{vivadoPath}'. Please start manually!
+
+ Press any key to exit.
+ """))
+
+ # wait on user interaction
+ input()
+ exit(1)
+
+
+# Entry point
+if __name__ == "__main__":
+ main()
+
+
+
+
+
diff --git a/typing/index.html b/typing/index.html
new file mode 100644
index 0000000..bfc8f13
--- /dev/null
+++ b/typing/index.html
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
Mypy Type Check Coverage Summary
+
+Summary from index
+
+File
+Imprecision
+Lines
+
+
+Total
+0.53% imprecise
+189 LOC
+
+
+pyEDAA.Launcher
+0.53% imprecise
+189 LOC
+
+
+
+
diff --git a/typing/mypy-html.css b/typing/mypy-html.css
new file mode 100644
index 0000000..ec2bdf9
--- /dev/null
+++ b/typing/mypy-html.css
@@ -0,0 +1,104 @@
+/* CSS for type check coverage reports */
+
+/*
+ Used by both summary and file.
+*/
+body {
+ font-family: "Helvetica Neue", sans-serif;
+}
+
+/*
+ Used only by summary.
+*/
+
+h1 {
+ text-align: center;
+ font-size: 135%;
+ margin: 20px;
+}
+
+table.summary {
+ border-collapse: collapse;
+ margin-left: 7%;
+ margin-right: 7%;
+ width: 85%;
+}
+
+table caption {
+ margin: 1em;
+}
+
+table.summary, tr.summary, th.summary, td.summary {
+ border: 1px solid #aaa;
+}
+
+th.summary, td.summary {
+ padding: 0.4em;
+}
+
+td.summary a {
+ text-decoration: none;
+}
+
+.summary-quality-0 {
+ background-color: #dfd;
+}
+
+.summary-quality-1 {
+ background-color: #ffa;
+}
+
+.summary-quality-2 {
+ background-color: #faa;
+}
+
+td.summary-filename, th.summary-filename {
+ text-align: left;
+}
+
+td.summary-filename {
+ width: 50%;
+}
+
+.summary-precision {
+ text-align: center;
+}
+
+.summary-lines {
+ text-align: center;
+}
+
+/*
+ Used only by file.
+*/
+
+td.table-lines {
+ text-align: right;
+ padding-right: 0.5em;
+}
+
+td.table-code { }
+
+span.lineno {
+ text-align: right;
+}
+
+a:link.lineno, a:visited.lineno {
+ color: #999; text-decoration: none;
+}
+
+a:hover.lineno, a:active.lineno {
+ color: #000; text-decoration: underline;
+}
+
+.line-empty, .line-precise {
+ background-color: #dfd;
+}
+
+.line-imprecise {
+ background-color: #ffa;
+}
+
+.line-any, .line-unanalyzed {
+ background-color: #faa;
+}
diff --git a/unittests/index.html b/unittests/index.html
new file mode 100644
index 0000000..b495fe2
--- /dev/null
+++ b/unittests/index.html
@@ -0,0 +1,224 @@
+
+
+
+
+
+
+
+
+
Unittest Summary Report — pyEDAA.Launcher 0.1.0 documentation
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ pyEDAA.Launcher
+
+
+
+
+
+
+
+
+
+Unittest Summary Report
+Unittest report generated with pytest .
+
+
+
+Testsuite / Testcase
+Testcases
+Skipped
+Errored
+Failed
+Passed
+Assertions
+Runtime (HH:MM:SS.sss)
+
+
+
+✅pytest
+1
+0
+0
+0
+1
+
+00:00:00.218
+
+ ✅tests
+1
+0
+0
+0
+1
+
+00:00:00.002
+
+ ✅unit
+1
+0
+0
+0
+1
+
+00:00:00.002
+
+ ✅Vivado
+1
+0
+0
+0
+1
+
+00:00:00.002
+
+ ✅ReadXPRFile
+1
+0
+0
+0
+1
+
+00:00:00.002
+
+ ✅test_ExtractVersionFromXPRFile
+
+
+
+
+
+0
+00:00:00.002
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file