2024-02-17 21:59:50 +00:00
<!DOCTYPE html>
< html xmlns = "http://www.w3.org/1999/xhtml" lang = "en" xml:lang = "en" >< head >
< meta charset = "utf-8" >
2026-03-21 01:32:33 +00:00
< meta name = "generator" content = "quarto-1.9.36" >
2024-02-17 21:59:50 +00:00
< meta name = "viewport" content = "width=device-width, initial-scale=1.0, user-scalable=yes" >
2024-08-11 21:05:44 +00:00
< title > Projects – Awesome Quant</ title >
2024-02-17 21:59:50 +00:00
< style >
2026-03-21 01:32:33 +00:00
/* Default styles provided by pandoc.
** See https://pandoc.org/MANUAL.html#variables-for-html for config info.
*/
2024-02-17 21:59:50 +00:00
code { white-space : pre-wrap ;}
span . smallcaps { font-variant : small-caps ;}
div . columns { display : flex ; gap : min ( 4 vw , 1.5 em );}
div . column { flex : auto ; overflow-x : auto ;}
div . hanging-indent { margin-left : 1.5 em ; text-indent : -1.5 em ;}
ul . task-list { list-style : none ;}
ul . task-list li input [ type = "checkbox" ] {
width : 0.8 em ;
margin : 0 0.8 em 0.2 em -1 em ; /* quarto-specific, see https://github.com/quarto-dev/quarto-cli/issues/4556 */
vertical-align : middle ;
}
</ style >
< script src = "site_libs/quarto-nav/quarto-nav.js" ></ script >
< script src = "site_libs/quarto-nav/headroom.min.js" ></ script >
< script src = "site_libs/clipboard/clipboard.min.js" ></ script >
< script src = "site_libs/quarto-search/autocomplete.umd.js" ></ script >
< script src = "site_libs/quarto-search/fuse.min.js" ></ script >
< script src = "site_libs/quarto-search/quarto-search.js" ></ script >
< meta name = "quarto:offset" content = "./" >
2025-04-30 02:26:32 +00:00
< script src = "site_libs/quarto-html/quarto.js" type = "module" ></ script >
< script src = "site_libs/quarto-html/tabsets/tabsets.js" type = "module" ></ script >
2024-02-17 21:59:50 +00:00
< script src = "site_libs/quarto-html/popper.min.js" ></ script >
< script src = "site_libs/quarto-html/tippy.umd.min.js" ></ script >
< script src = "site_libs/quarto-html/anchor.min.js" ></ script >
< link href = "site_libs/quarto-html/tippy.css" rel = "stylesheet" >
2026-03-21 01:32:33 +00:00
< link href = "site_libs/quarto-html/quarto-syntax-highlighting-845c23b38eaddc0f92fda52bfe77a8c8.css" rel = "stylesheet" id = "quarto-text-highlighting-styles" >
2024-02-17 21:59:50 +00:00
< script src = "site_libs/bootstrap/bootstrap.min.js" ></ script >
< link href = "site_libs/bootstrap/bootstrap-icons.css" rel = "stylesheet" >
2026-03-21 01:32:33 +00:00
< link href = "site_libs/bootstrap/bootstrap-dea667461a5c81afc9ba75ce94cd63f3.min.css" rel = "stylesheet" append-hash = "true" id = "quarto-bootstrap" data-mode = "light" >
2024-02-17 21:59:50 +00:00
< script id = "quarto-search-options" type = "application/json" >{
"location" : "navbar" ,
"copy-button" : false ,
"collapse-after" : 3 ,
"panel-placement" : "end" ,
"type" : "overlay" ,
"limit" : 50 ,
"keyboard-shortcut" : [
"f" ,
"/" ,
"s"
],
"show-item-context" : false ,
"language" : {
"search-no-results-text" : "No results" ,
"search-matching-documents-text" : "matching documents" ,
"search-copy-link-title" : "Copy link to search" ,
"search-hide-matches-text" : "Hide additional matches" ,
"search-more-match-text" : "more match in this document" ,
"search-more-matches-text" : "more matches in this document" ,
"search-clear-button-title" : "Clear" ,
"search-text-placeholder" : "" ,
"search-detached-cancel-button-title" : "Cancel" ,
"search-submit-button-title" : "Submit" ,
"search-label" : "Search"
}
}</ script >
2025-12-05 01:38:43 +00:00
< link href = "site_libs/htmltools-fill-0.5.9/fill.css" rel = "stylesheet" >
2024-02-17 21:59:50 +00:00
< script src = "site_libs/htmlwidgets-1.6.4/htmlwidgets.js" ></ script >
< link href = "site_libs/datatables-css-0.0.0/datatables-crosstalk.css" rel = "stylesheet" >
2025-09-03 01:30:43 +00:00
< script src = "site_libs/datatables-binding-0.34.0/datatables.js" ></ script >
2024-02-17 21:59:50 +00:00
< script src = "site_libs/jquery-3.6.0/jquery-3.6.0.min.js" ></ script >
< link href = "site_libs/dt-core-1.13.6/css/jquery.dataTables.min.css" rel = "stylesheet" >
< link href = "site_libs/dt-core-1.13.6/css/jquery.dataTables.extra.css" rel = "stylesheet" >
< script src = "site_libs/dt-core-1.13.6/js/jquery.dataTables.min.js" ></ script >
2025-08-27 01:30:38 +00:00
< link href = "site_libs/crosstalk-1.2.2/css/crosstalk.min.css" rel = "stylesheet" >
< script src = "site_libs/crosstalk-1.2.2/js/crosstalk.min.js" ></ script >
2024-02-17 21:59:50 +00:00
< script async = "" src = "https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-7994446359957143" crossorigin = "anonymous" ></ script >
< link rel = "stylesheet" href = "styles.css" >
</ head >
2025-04-30 02:26:32 +00:00
< body class = "nav-fixed quarto-light" >
2024-02-17 21:59:50 +00:00
< div id = "quarto-search-results" ></ div >
< header id = "quarto-header" class = "headroom fixed-top" >
< nav class = "navbar navbar-expand-lg " data-bs-theme = "dark" >
< div class = "navbar-container container-fluid" >
< div class = "navbar-brand-container mx-auto" >
< a class = "navbar-brand" href = "./index.html" >
< span class = "navbar-title" > Awesome Quant</ span >
</ a >
</ div >
< div id = "quarto-search" class = "" title = "Search" ></ div >
2024-08-11 21:05:44 +00:00
< button class = "navbar-toggler" type = "button" data-bs-toggle = "collapse" data-bs-target = "#navbarCollapse" aria-controls = "navbarCollapse" role = "menu" aria-expanded = "false" aria-label = "Toggle navigation" onclick = "if (window.quartoToggleHeadroom) { window.quartoToggleHeadroom(); }" >
2024-02-17 21:59:50 +00:00
< span class = "navbar-toggler-icon" ></ span >
</ button >
< div class = "collapse navbar-collapse" id = "navbarCollapse" >
< ul class = "navbar-nav navbar-nav-scroll me-auto" >
< li class = "nav-item" >
< a class = "nav-link" href = "./index.html" >
< span class = "menu-text" > Home</ span ></ a >
</ li >
< li class = "nav-item" >
< a class = "nav-link active" href = "./projects.html" aria-current = "page" >
< span class = "menu-text" > Projects</ span ></ a >
</ li >
< li class = "nav-item" >
< a class = "nav-link" href = "./CODE_OF_CONDUCT.html" >
< span class = "menu-text" > Code of Conduct</ span ></ a >
</ li >
</ ul >
</ div > <!-- /navcollapse -->
2024-08-11 21:05:44 +00:00
< div class = "quarto-navbar-tools" >
2024-02-17 21:59:50 +00:00
</ div >
</ div > <!-- /container-fluid -->
</ nav >
</ header >
<!-- content -->
< div id = "quarto-content" class = "quarto-container page-columns page-rows-contents page-layout-article page-navbar" >
<!-- sidebar -->
<!-- margin-sidebar -->
2024-08-11 21:05:44 +00:00
< div id = "quarto-margin-sidebar" class = "sidebar margin-sidebar zindex-bottom" >
2024-02-17 21:59:50 +00:00
</ div >
<!-- main -->
< main class = "content" id = "quarto-document-content" >
< header id = "title-block-header" class = "quarto-title-block default" >
< div class = "quarto-title" >
< h1 class = "title" > Projects</ h1 >
</ div >
< div class = "quarto-title-meta" >
</ div >
</ header >
< p > Compilation of projects providing access to the date of last commit or publication date.</ p >
2024-08-11 21:05:44 +00:00
< div id = "tbl-projects" class = "cell quarto-float quarto-figure quarto-figure-center anchored" data-table . cap = "Projects" >
2024-02-17 21:59:50 +00:00
< figure class = "quarto-float quarto-float-tbl figure" >
< figcaption class = "quarto-float-caption-top quarto-float-caption quarto-float-tbl" id = "tbl-projects-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca" >
Table 1: Projects
</ figcaption >
< div aria-describedby = "tbl-projects-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca" >
2026-03-21 01:32:33 +00:00
< div class = "datatables html-widget html-fill-item" id = "htmlwidget-668ac6415f1e596b81d8" style = "width:100%;height:auto;" ></ div >
< script type = "application/json" data-for = "htmlwidget-668ac6415f1e596b81d8" >{ "x" : { "filter" : "none" , "vertical" : false , "data" : [[ "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" , "190" , "191" , "192" , "193" , "194" , "195" , "196" , "197" , "198" , "199" , "200" , "201" , "202" , "203" , "204" , "205" , "206" , "207" , "208" , "209" , "210" , "211" , "212" , "213" , "214" , "215" , "216" , "217" , "218" , "219" , "220" , "221" , "222" , "223" , "224" , "225" , "226" , "227" , "228" , "229" , "230" , "231" , "232" , "233" , "234" , "235" , "236" , "237" , "238" , "239" , "240" , "241" , "242" , "243" , "244" , "245" , "246" , "247" , "248" , "249" , "250" , "251" , "252" , "253" , "254" , "255" , "256" , "257" , "258" , "259" , "260" , "261" , "262" , "263" , "264" , "265" , "266" , "267" , "268" , "269" , "270" , "271" , "272" , "273" , "274" , "275" , "276" , "277" , "278" , "279" , "280" , "281" , "282" , "283" , "284" , "285" , "286" , "287" , "288" , "289" , "290" , "291" , "292" , "293" , "294" , "295" , "296" , "297" , "298" , "299" , "300" , "301" , "302" , "303" , "304" , "305" , "306" , "307" , "308" , "309" , "310" , "311" , "312" , "313" , "314" , "315" , "316" , "317" , "318" , "319" , "320" , "321" , "322" , "323" , "324" , "325" , "326" , "327" , "328" , "329" , "330" , "331" , "332" , "333" , "334" , "335" , "336" , "337" , "338" , "339" , "340" , "341" , "342" , "343" , "344" , "345" , "346" , "347" , "348" , "349" , "350" , "351" , "352" , "353" , "354" , "355" , "356" , "357" , "358" , "359" , "360" , "361" , "362" , "363" , "364" , "365" , "366" , "367" , "368" , "369" , "370" , "371" , "372" , "373" , "374" , "375" , "376" , "377" ],[ "<a href='https://github.com/nautechsystems/nautilus_trader'>nautilus_trader<\/a>" , "<a href='https://github.com/man-group/ArcticDB'>ArcticDB<\/a>" , "<a href='https://github.com/pmxt-dev/pmxt'>pmxt<\/a>" , "<a href='https://github.com/Fincept-Corporation/FinceptTerminal'>Fincept Terminal<\/a>" , "<a href='https://github.com/pmorissette/ffn'>ffn<\/a>" , "<a href='https://github.com/alexanderwanyoike/the0'>the0<\/a>" , "<a href='https://github.com/coding-kitties/investing-algorithm-framework'>Investing algorithm framework<\/a>" , "<a href='https://github.com/dragon1086/prism-insight'>PRISM-INSIGHT<\/a>" , "<a href='https://github.com/AI4Finance-LLC/FinRL-Library'>FinRL-Library<\/a>" , "<a href='https://github.com/fasiondog/hikyuu'>Hikyuu<\/a>" , "<a href='https://github.com/cuemacro/findatapy'>findatapy<\/a>" , "<a href='https://github.com/jindaxiang/akshare'>akshare<\/a>" , "<a href='https://github.com/dgunning/edgartools'>edgartools<\/a>" , "<a href='https://github.com/ccxt/ccxt'>ccxt<\/a>" , "<a href='https://github.com/pmxt-dev/pmxt'>pmxt<\/a>" , "<a href='https://github.com/qoery-com/pmxt'>pmxt<\/a>" , "<a href='https://github.com/fasiondog/hikyuu'>Hikyuu<\/a>" , "<a href='https://github.com/StockSharp/StockSharp'>StockSharp<\/a>" , "<a href='https://github.com/runmat-org/runmat'>RunMat<\/a>" , "<a href='https://github.com/OpenBB-finance/OpenBBTerminal'>OpenBB Terminal<\/a>" , "<a href='https://github.com/goldmansachs/gs-quant'>gs-quant<\/a>" , "<a href='https://github.com/freqtrade/freqtrade'>freqtrade<\/a>" , "<a href='https://github.com/polakowo/vectorbt'>vectorbt<\/a>" , "<a href='https://github.com/robcarver17/pysystemtrade'>pysystemtrade<\/a>" , "<a href='https://github.com/rafa-rod/pytrendseries'>pytrendseries<\/a>" , "<a href='https://github.com/tradingstrategy-ai/getting-started'>Trading Strategy<\/a>" , "<a href='https://
2024-02-17 21:59:50 +00:00
</div>
</figure>
</div>
</main> <!-- /main -->
<script id=" quarto - html - after - body " type=" application / javascript ">
2025-04-30 02:26:32 +00:00
window.document.addEventListener(" DOMContentLoaded ", function (event) {
const icon = " ";
const anchorJS = new window.AnchorJS();
anchorJS.options = {
placement: 'right',
icon: icon
};
anchorJS.add('.anchored');
const isCodeAnnotation = (el) => {
for (const clz of el.classList) {
if (clz.startsWith('code-annotation-')) {
return true;
}
2024-02-17 21:59:50 +00:00
}
2025-04-30 02:26:32 +00:00
return false;
2024-02-17 21:59:50 +00:00
}
2025-04-30 02:26:32 +00:00
const onCopySuccess = function(e) {
// button target
const button = e.trigger;
// don't keep focus
button.blur();
// flash " checked "
button.classList.add('code-copy-button-checked');
var currentTitle = button.getAttribute(" title ");
button.setAttribute(" title ", " Copied ! ");
let tooltip;
if (window.bootstrap) {
button.setAttribute(" data - bs - toggle ", " tooltip ");
button.setAttribute(" data - bs - placement ", " left ");
button.setAttribute(" data - bs - title ", " Copied ! ");
tooltip = new bootstrap.Tooltip(button,
{ trigger: " manual ",
customClass: " code - copy - button - tooltip ",
offset: [0, -8]});
tooltip.show();
2024-02-17 21:59:50 +00:00
}
2025-04-30 02:26:32 +00:00
setTimeout(function() {
if (tooltip) {
tooltip.hide();
button.removeAttribute(" data - bs - title ");
button.removeAttribute(" data - bs - toggle ");
button.removeAttribute(" data - bs - placement ");
2024-08-11 21:05:44 +00:00
}
2025-04-30 02:26:32 +00:00
button.setAttribute(" title ", currentTitle);
button.classList.remove('code-copy-button-checked');
}, 1000);
// clear code selection
e.clearSelection();
2024-08-11 21:05:44 +00:00
}
2025-04-30 02:26:32 +00:00
const getTextToCopy = function(trigger) {
2025-09-13 01:31:25 +00:00
const outerScaffold = trigger.parentElement.cloneNode(true);
const codeEl = outerScaffold.querySelector('code');
for (const childEl of codeEl.children) {
if (isCodeAnnotation(childEl)) {
childEl.remove();
2024-08-11 21:05:44 +00:00
}
2025-09-13 01:31:25 +00:00
}
return codeEl.innerText;
2024-02-17 21:59:50 +00:00
}
2025-04-30 02:26:32 +00:00
const clipboard = new window.ClipboardJS('.code-copy-button:not([data-in-quarto-modal])', {
text: getTextToCopy
});
clipboard.on('success', onCopySuccess);
if (window.document.getElementById('quarto-embedded-source-code-modal')) {
const clipboardModal = new window.ClipboardJS('.code-copy-button[data-in-quarto-modal]', {
text: getTextToCopy,
container: window.document.getElementById('quarto-embedded-source-code-modal')
});
clipboardModal.on('success', onCopySuccess);
2024-02-17 21:59:50 +00:00
}
2025-04-30 02:26:32 +00:00
var localhostRegex = new RegExp(/^(?:http|https):\/\/localhost\:?[0-9]*\//);
var mailtoRegex = new RegExp(/^mailto:/);
var filterRegex = new RegExp('/' + window.location.host + '/');
var isInternal = (href) => {
return filterRegex.test(href) || localhostRegex.test(href) || mailtoRegex.test(href);
2024-08-11 21:05:44 +00:00
}
2025-04-30 02:26:32 +00:00
// Inspect non-navigation links and adorn them if external
var links = window.document.querySelectorAll('a[href]:not(.nav-link):not(.navbar-brand):not(.toc-action):not(.sidebar-link):not(.sidebar-item-toggle):not(.pagination-link):not(.no-external):not([aria-hidden]):not(.dropdown-item):not(.quarto-navigation-tool):not(.about-link)');
for (var i=0; i<links.length; i++) {
const link = links[i];
if (!isInternal(link.href)) {
// undo the damage that might have been done by quarto-nav.js in the case of
// links that we want to consider external
if (link.dataset.originalHref !== undefined) {
link.href = link.dataset.originalHref;
}
2024-02-17 21:59:50 +00:00
}
}
2025-04-30 02:26:32 +00:00
function tippyHover(el, contentFn, onTriggerFn, onUntriggerFn) {
const config = {
allowHTML: true,
maxWidth: 500,
delay: 100,
arrow: false,
appendTo: function(el) {
return el.parentElement;
},
interactive: true,
interactiveBorder: 10,
theme: 'quarto',
placement: 'bottom-start',
};
if (contentFn) {
config.content = contentFn;
}
if (onTriggerFn) {
config.onTrigger = onTriggerFn;
}
if (onUntriggerFn) {
config.onUntrigger = onUntriggerFn;
}
window.tippy(el, config);
2024-02-17 21:59:50 +00:00
}
2025-04-30 02:26:32 +00:00
const noterefs = window.document.querySelectorAll('a[role=" doc - noteref "]');
for (var i=0; i<noterefs.length; i++) {
const ref = noterefs[i];
tippyHover(ref, function() {
// use id or data attribute instead here
let href = ref.getAttribute('data-footnote-href') || ref.getAttribute('href');
try { href = new URL(href).hash; } catch {}
const id = href.replace(/^#\/?/, "");
const note = window.document.getElementById(id);
if (note) {
return note.innerHTML;
} else {
return "";
}
});
}
const xrefs = window.document.querySelectorAll('a.quarto-xref');
const processXRef = (id, note) => {
// Strip column container classes
const stripColumnClz = (el) => {
el.classList.remove(" page - full ", " page - columns ");
if (el.children) {
for (const child of el.children) {
stripColumnClz(child);
2024-02-17 21:59:50 +00:00
}
}
2025-04-30 02:26:32 +00:00
}
stripColumnClz(note)
if (id === null || id.startsWith('sec-')) {
// Special case sections, only their first couple elements
const container = document.createElement(" div ");
if (note.children && note.children.length > 2) {
container.appendChild(note.children[0].cloneNode(true));
for (let i = 1; i < note.children.length; i++) {
const child = note.children[i];
if (child.tagName === " P " && child.innerText === "") {
continue;
} else {
container.appendChild(child.cloneNode(true));
break;
}
}
if (window.Quarto?.typesetMath) {
window.Quarto.typesetMath(container);
}
return container.innerHTML
} else {
if (window.Quarto?.typesetMath) {
window.Quarto.typesetMath(note);
}
return note.innerHTML;
2024-02-17 21:59:50 +00:00
}
} else {
2025-04-30 02:26:32 +00:00
// Remove any anchor links if they are present
const anchorLink = note.querySelector('a.anchorjs-link');
if (anchorLink) {
anchorLink.remove();
}
2024-02-17 21:59:50 +00:00
if (window.Quarto?.typesetMath) {
window.Quarto.typesetMath(note);
}
2025-04-30 02:26:32 +00:00
if (note.classList.contains(" callout ")) {
return note.outerHTML;
} else {
return note.innerHTML;
}
2024-02-17 21:59:50 +00:00
}
}
2025-04-30 02:26:32 +00:00
for (var i=0; i<xrefs.length; i++) {
const xref = xrefs[i];
tippyHover(xref, undefined, function(instance) {
instance.disable();
let url = xref.getAttribute('href');
let hash = undefined;
if (url.startsWith('#')) {
hash = url;
} else {
try { hash = new URL(url).hash; } catch {}
}
if (hash) {
const id = hash.replace(/^#\/?/, "");
const note = window.document.getElementById(id);
if (note !== null) {
try {
const html = processXRef(id, note.cloneNode(true));
instance.setContent(html);
} finally {
instance.enable();
instance.show();
}
} else {
// See if we can fetch this
fetch(url.split('#')[0])
.then(res => res.text())
.then(html => {
const parser = new DOMParser();
const htmlDoc = parser.parseFromString(html, " text / html ");
const note = htmlDoc.getElementById(id);
if (note !== null) {
const html = processXRef(id, note);
instance.setContent(html);
}
}).finally(() => {
instance.enable();
instance.show();
});
2024-02-17 21:59:50 +00:00
}
} else {
2025-04-30 02:26:32 +00:00
// See if we can fetch a full url (with no hash to target)
// This is a special case and we should probably do some content thinning / targeting
fetch(url)
2024-02-17 21:59:50 +00:00
.then(res => res.text())
.then(html => {
const parser = new DOMParser();
const htmlDoc = parser.parseFromString(html, " text / html ");
2025-04-30 02:26:32 +00:00
const note = htmlDoc.querySelector('main.content');
2024-02-17 21:59:50 +00:00
if (note !== null) {
2025-04-30 02:26:32 +00:00
// This should only happen for chapter cross references
// (since there is no id in the URL)
// remove the first header
if (note.children.length > 0 && note.children[0].tagName === " HEADER ") {
note.children[0].remove();
}
const html = processXRef(null, note);
2024-02-17 21:59:50 +00:00
instance.setContent(html);
}
}).finally(() => {
instance.enable();
instance.show();
});
}
2025-04-30 02:26:32 +00:00
}, function(instance) {
});
}
let selectedAnnoteEl;
const selectorForAnnotation = ( cell, annotation) => {
let cellAttr = 'data-code-cell=" ' + cell + ' "';
let lineAttr = 'data-code-annotation=" ' + annotation + ' "';
const selector = 'span[' + cellAttr + '][' + lineAttr + ']';
return selector;
}
const selectCodeLines = (annoteEl) => {
const doc = window.document;
const targetCell = annoteEl.getAttribute(" data - target - cell ");
const targetAnnotation = annoteEl.getAttribute(" data - target - annotation ");
const annoteSpan = window.document.querySelector(selectorForAnnotation(targetCell, targetAnnotation));
const lines = annoteSpan.getAttribute(" data - code - lines ").split(" , ");
const lineIds = lines.map((line) => {
return targetCell + " - " + line;
})
let top = null;
let height = null;
let parent = null;
if (lineIds.length > 0) {
//compute the position of the single el (top and bottom and make a div)
const el = window.document.getElementById(lineIds[0]);
top = el.offsetTop;
height = el.offsetHeight;
parent = el.parentElement.parentElement;
if (lineIds.length > 1) {
const lastEl = window.document.getElementById(lineIds[lineIds.length - 1]);
const bottom = lastEl.offsetTop + lastEl.offsetHeight;
height = bottom - top;
2024-02-17 21:59:50 +00:00
}
2025-04-30 02:26:32 +00:00
if (top !== null && height !== null && parent !== null) {
// cook up a div (if necessary) and position it
let div = window.document.getElementById(" code - annotation - line - highlight ");
if (div === null) {
div = window.document.createElement(" div ");
div.setAttribute(" id ", " code - annotation - line - highlight ");
div.style.position = 'absolute';
parent.appendChild(div);
}
div.style.top = top - 2 + " px ";
div.style.height = height + 4 + " px ";
div.style.left = 0;
let gutterDiv = window.document.getElementById(" code - annotation - line - highlight - gutter ");
if (gutterDiv === null) {
gutterDiv = window.document.createElement(" div ");
gutterDiv.setAttribute(" id ", " code - annotation - line - highlight - gutter ");
gutterDiv.style.position = 'absolute';
const codeCell = window.document.getElementById(targetCell);
const gutter = codeCell.querySelector('.code-annotation-gutter');
gutter.appendChild(gutterDiv);
}
gutterDiv.style.top = top - 2 + " px ";
gutterDiv.style.height = height + 4 + " px ";
2024-02-17 21:59:50 +00:00
}
2025-04-30 02:26:32 +00:00
selectedAnnoteEl = annoteEl;
2024-02-17 21:59:50 +00:00
}
2025-04-30 02:26:32 +00:00
};
const unselectCodeLines = () => {
const elementsIds = [" code - annotation - line - highlight ", " code - annotation - line - highlight - gutter "];
elementsIds.forEach((elId) => {
const div = window.document.getElementById(elId);
if (div) {
div.remove();
}
});
selectedAnnoteEl = undefined;
};
// Handle positioning of the toggle
window.addEventListener(
" resize ",
throttle(() => {
elRect = undefined;
if (selectedAnnoteEl) {
selectCodeLines(selectedAnnoteEl);
2024-02-17 21:59:50 +00:00
}
2025-04-30 02:26:32 +00:00
}, 10)
);
function throttle(fn, ms) {
let throttle = false;
let timer;
return (...args) => {
if(!throttle) { // first call gets through
2024-02-17 21:59:50 +00:00
fn.apply(this, args);
2025-04-30 02:26:32 +00:00
throttle = true;
} else { // all the others get throttled
if(timer) clearTimeout(timer); // cancel #2
timer = setTimeout(() => {
fn.apply(this, args);
timer = throttle = false;
}, ms);
2024-02-17 21:59:50 +00:00
}
};
2025-04-30 02:26:32 +00:00
}
// Attach click handler to the DT
const annoteDls = window.document.querySelectorAll('dt[data-target-cell]');
for (const annoteDlNode of annoteDls) {
annoteDlNode.addEventListener('click', (event) => {
const clickedEl = event.target;
if (clickedEl !== selectedAnnoteEl) {
unselectCodeLines();
const activeEl = window.document.querySelector('dt[data-target-cell].code-annotation-active');
if (activeEl) {
activeEl.classList.remove('code-annotation-active');
}
selectCodeLines(clickedEl);
clickedEl.classList.add('code-annotation-active');
} else {
// Unselect the line
unselectCodeLines();
clickedEl.classList.remove('code-annotation-active');
}
});
}
const findCites = (el) => {
const parentEl = el.parentElement;
if (parentEl) {
const cites = parentEl.dataset.cites;
if (cites) {
return {
el,
cites: cites.split(' ')
};
} else {
return findCites(el.parentElement)
}
2024-02-17 21:59:50 +00:00
} else {
2025-04-30 02:26:32 +00:00
return undefined;
2024-02-17 21:59:50 +00:00
}
2025-04-30 02:26:32 +00:00
};
var bibliorefs = window.document.querySelectorAll('a[role=" doc - biblioref " ] ');
for (var i=0; i<bibliorefs.length; i++) {
const ref = bibliorefs[i];
const citeInfo = findCites(ref);
if (citeInfo) {
tippyHover(citeInfo.el, function() {
var popup = window.document.createElement(' div ');
citeInfo.cites.forEach(function(cite) {
var citeDiv = window.document.createElement(' div ');
citeDiv.classList.add(' hanging - indent ');
citeDiv.classList.add(' csl - entry ');
var biblioDiv = window.document.getElementById(' ref - ' + cite );
if ( biblioDiv ) {
citeDiv . innerHTML = biblioDiv . innerHTML ;
}
popup . appendChild ( citeDiv );
});
return popup . innerHTML ;
2024-02-17 21:59:50 +00:00
});
2025-04-30 02:26:32 +00:00
}
2024-02-17 21:59:50 +00:00
}
2025-04-30 02:26:32 +00:00
});
</ script >
2024-02-17 21:59:50 +00:00
</ div > <!-- /content -->
</ body ></ html >