1<!DOCTYPE html> 2<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en"><head> 3 4<meta charset="utf-8"> 5<meta name="generator" content="quarto-1.6.39"> 6 7<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes"> 8 9 10<title>Projects â Elisabetta Pietrostefani</title> 11<style> 12code{white-space: pre-wrap;} 13span.smallcaps{font-variant: small-caps;} 14div.columns{display: flex; gap: min(4vw, 1.5em);} 15div.column{flex: auto; overflow-x: auto;} 16div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;} 17ul.task-list{list-style: none;} 18ul.task-list li input[type="checkbox"] { 19 width: 0.8em; 20 margin: 0 0.8em 0.2em -1em; /* quarto-specific, see https://github.com/quarto-dev/quarto-cli/issues/4556 */ 21 vertical-align: middle; 22} 23</style> 24 25
26<script src="site_libs/quarto-nav/quarto-nav.js"></script>
vendor: 1 bytes, line 26
26
27<script src="site_libs/clipboard/clipboard.min.js"></script>
vendor: 1 bytes, line 27
27
28<script src="site_libs/quarto-search/autocomplete.umd.js"></script>
vendor: 1 bytes, line 28
28
29<script src="site_libs/quarto-search/fuse.min.js"></script>
vendor: 1 bytes, line 29
29
30<script src="site_libs/quarto-search/quarto-search.js"></script>
30 31<meta name="quarto:offset" content="./"> 32<link href="./assets/favicon.svg" rel="icon" type="image/svg+xml">
33<script src="site_libs/quarto-html/quarto.js"></script>
vendor: 1 bytes, line 33
33
34<script src="site_libs/quarto-html/popper.min.js"></script>
vendor: 1 bytes, line 34
34
35<script src="site_libs/quarto-html/tippy.umd.min.js"></script>
35 36<link href="site_libs/quarto-html/tippy.css" rel="stylesheet"> 37<link href="site_libs/quarto-html/quarto-syntax-highlighting-e26003cea8cd680ca0c55a263523d882.css" rel="stylesheet" id="quarto-text-highlighting-styles">
38<script src="site_libs/bootstrap/bootstrap.min.js"></script>
38 39<link href="site_libs/bootstrap/bootstrap-icons.css" rel="stylesheet"> 40<link href="site_libs/bootstrap/bootstrap-518349efc12e5c6411259d03c752f14e.min.css" rel="stylesheet" append-hash="true" id="quarto-bootstrap" data-mode="light">
41<script id="quarto-search-options" type="application/json">{ 42 "location": "navbar", 43 "copy-button": false, 44 "collapse-after": 3, 45 "panel-placement": "end", 46 "type": "overlay", 47 "limit": 50, 48 "keyboard-shortcut": [ 49 "f", 50 "/", 51 "s" 52 ], 53 "show-item-context": false, 54 "language": { 55 "search-no-results-text": "No results", 56 "search-matching-documents-text": "matching documents", 57 "search-copy-link-title": "Copy link to search", 58 "search-hide-matches-text": "Hide additional matches", 59 "search-more-match-text": "more match in this document", 60 "search-more-matches-text": "more matches in this document", 61 "search-clear-button-title": "Clear", 62 "search-text-placeholder": "", 63 "search-detached-cancel-button-title": "Cancel", 64 "search-submit-button-title": "Submit", 65 "search-label": "Search" 66 } 67}</script>
67 68<style>html{ scroll-behavior: smooth; }</style> 69<link rel="icon" href="./favicon.ico?v=4" sizes="any"> 70<link rel="shortcut icon" href="./favicon.ico?v=4" type="image/x-icon"> 71<link rel="icon" href="./favicon-v3.ico" sizes="any"> 72<link rel="icon" href="./assets/favicon.svg?v=4" type="image/svg+xml"> 73<link rel="apple-touch-icon" href="./apple-touch-icon.png?v=4"> 74 75 76</head> 77 78<body class="nav-fixed fullcontent"> 79 80<div id="quarto-search-results"></div> 81 <header id="quarto-header" class="headroom fixed-top"> 82 <nav class="navbar navbar-expand-lg " data-bs-theme="dark"> 83 <div class="navbar-container container-fluid"> 84 <div class="navbar-brand-container mx-auto"> 85 <a class='navbar-brand' href='/'> 86 <span class="navbar-title">Elisabetta Pietrostefani</span> 87 </a> 88 </div> 89 <div id="quarto-search" class="" title="Search"></div> 90 <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(); }"> 91 <span class="navbar-toggler-icon"></span> 92</button> 93 <div class="collapse navbar-collapse" id="navbarCollapse"> 94 <ul class="navbar-nav navbar-nav-scroll me-auto"> 95 <li class="nav-item"> 96 <a aria-current='page' class='nav-link active' href='/projects'> 97<span class="menu-text">Projects</span></a> 98 </li> 99 <li class="nav-item"> 100 <a class='nav-link' href='/papers'> 101<span class="menu-text">Publications</span></a> 102 </li> 103 <li class="nav-item"> 104 <a class='nav-link' href='/courses'> 105<span class="menu-text">Teaching</span></a> 106 </li> 107 <li class="nav-item"> 108 <a class='nav-link' href='/log'> 109<span class="menu-text">Log</span></a> 110 </li> 111</ul> 112 </div> <!-- /navcollapse --> 113 <div class="quarto-navbar-tools"> 114</div> 115 </div> <!-- /container-fluid --> 116 </nav> 117</header> 118<!-- content --> 119<div id="quarto-content" class="quarto-container page-columns page-rows-contents page-layout-article page-navbar"> 120<!-- sidebar --> 121<!-- margin-sidebar --> 122 123<!-- main --> 124<main class="content" id="quarto-document-content"> 125 126<header id="title-block-header" class="quarto-title-block default"> 127<div class="quarto-title"> 128<h1 class="title">Projects</h1> 129</div> 130 131 132 133<div class="quarto-title-meta"> 134 135 136 137 138 </div> 139 140 141 142</header> 143 144 145<!-- 146 STANDARD CARD FORMAT: 147 - Description in <span class="meta">...</span> 148 - Ends with two sentences: "Funded by X." and "With Y." 149 - Link is either: 150 * [Project website](url) â external project site 151 * [Learn more](page.qmd) â internal deep-dive page 152 153 Papers, reports, and additional links live on the internal .qmd 154 deep-dive pages, NOT on these cards. 155 156 Screenshots: drop images at `content/projects/<slug>.<ext>` and 157 reference with {fig-alt="..."} as first line of card. 158 159 Internal pages required (create these as .qmd files at repo root): 160 - beirut-blast.qmd (exists) 161 - displacement.qmd 162 - economics-of-architecture.qmd 163 - density.qmd 164 - evaluating-urban-policy.qmd 165 - informal-labour.qmd 166 - quality-of-life-lebanon.qmd 167 - fipal.qmd 168--> 169<p>Elisabettaâs work spans several research threads on urban shocks, inequality, and displacement. A selection is below; a full list of grants and collaborations is on the <a href="assets/cv.pdf">CV</a>.</p> 170<div class="media-grid"> 171<div class="media-card"> 172<p><img src="content/projects/imago.png" class="img-fluid" alt="Satellite imagery over a city"></p> 173<section id="imago" class="level3"> 174<h3 data-anchor-id="imago">IMAGO</h3> 175<p><span class="meta">The SDR-UK Imagery Data Service for Sustainability, Prosperity and Wellbeing. Making satellite imagery useful, usable and used across social research and policy â through data infrastructure, applied case studies, and researcher training. Funded by UKRI ESRC (2024â2029). </span></p> 176<p><a href="https://imago.ac.uk">Project website</a></p> 177</section> 178</div> 179<div class="media-card"> 180<p><img src="content/projects/displacement_disaster.png" class="img-fluid" alt="Map of displacement flows"></p> 181<section id="displacement-in-disaster-regions" class="level3"> 182<h3 data-anchor-id="displacement-in-disaster-regions">Displacement in disaster regions</h3> 183<p><span class="meta">Developing methods to estimate internal displacement in real time by triangulating satellite imagery, mobile phone GPS data, and traditional surveys. Applications include the Russo-Ukrainian War and other disaster-affected contexts. Funded by Research England and ESRC. With IOM-DTM, UK government partners, Francisco Rowe, Matt Mason, Rodgers Iradukunda & Andrea Nasuto.</span></p> 184<p><a href="https://pietrostefani.github.io/pop-displacement-disaster/">Project Website</a></p> 185</section> 186</div> 187<div class="media-card"> 188<p><img src="content/projects/floodtraces.png" class="img-fluid" alt="Satellite imagery of flooded terrain"></p> 189<section id="floodtraces" class="level3"> 190<h3 data-anchor-id="floodtraces">FloodTraces</h3> 191<p><span class="meta">Integrating traditional and digital trace data â satellite imagery, mobile phone signals, and social media â for real-time humanitarian decision-making in flood-affected regi
191ons. Funded by Research England (2025â2026). With IOM-DTM and UK government partners.</span></p> 192<p><a href="https://pietrostefani.github.io/floodtraces-hack/">Project website</a></p> 193</section> 194</div> 195<div class="media-card"> 196<p><img src="content/projects/beirut_blast.png" class="img-fluid" alt="Aerial view of Beirut showing blast damage"></p> 197<section id="post-blast-beirut" class="level3"> 198<h3 data-anchor-id="post-blast-beirut">Post-Blast Beirut</h3> 199<p><span class="meta">Investigating how the 4 August 2020 Beirut Blast reshaped vulnerability and inequality across the city. Combines spatial survey data collected in 2018 and 2021 with satellite-derived building damage assessments to track fine-grained changes in urban well-being and household resilience. Funded by GCRF and UCL Small Grants. With <a href="https://www.ucl.ac.uk/bartlett/global-prosperity">UCLâs Institute for Global Prosperity</a>, <a href="https://catalyticaction.org/assessing-vulnerabilities-in-beirut-post-explosion/">CatalyticAction</a> and Yara Sleiman.</span></p> 200<p><a href='/beirut-blast'>Learn more</a></p> 201</section> 202</div> 203<div class="media-card"> 204<p><img src="content/projects/archi.jpg" class="img-fluid" alt="Architectural detail of a European city"></p> 205<section id="economics-of-architecture" class="level3"> 206<h3 data-anchor-id="economics-of-architecture">Economics of Architecture</h3> 207<p><span class="meta">Do buildings and architectural quality shape economic outcomes in cities? An emerging research thread on high-quality Baukultur, real estate values, and long-term urban outcomes. Funded by the Swiss Federal Office of Culture. With Gabriel Ahlfeldt and Ailin Zhang.</span></p> 208<p><a href='/economics-of-architecture'>Learn more</a></p> 209</section> 210</div> 211<div class="media-card"> 212<p><img src="content/projects/density.jpg" class="img-fluid" alt="Dense urban skyline"></p> 213<section id="density" class="level3"> 214<h3 data-anchor-id="density">Density</h3> 215<p><span class="meta">A research strand on the economic effects of urban density â from a meta-analytic synthesis of 300+ studies globally to policy work on compact urban growth. Some funded by the OECD. With Gabriel Ahlfeldt, OECD, and the World Resources Institute.</span></p> 216<p><a href='/density'>Learn more</a></p> 217</section> 218</div> 219<div class="media-card"> 220<p><img src="content/projects/Fig_1_OMI+and+re-allocated+assets.jpeg" class="img-fluid" alt="Historic building in an Italian city"></p> 221<section id="evaluating-urban-policy" class="level3"> 222<h3 data-anchor-id="evaluating-urban-policy">Evaluating Urban Policy</h3> 223<p><span class="meta">Assessing the causal effects of urban policies on economic and social outcomes â from confiscated mafia real estate assets reallocated to communities in Italy, to conservation planning regulations and the politics of urban heritage across the Global North and South. Funded by LSE and the RGS-IBG. With Filippo Boeri, Marco Di Cataldo, and Nancy Holman.</span></p> 224<p><a href='/evaluating-urban-policy'>Learn more</a></p> 225</section> 226</div> 227<div class="media-card"> 228<p><img src="content/projects/DCE_picture.jpg" class="img-fluid" alt="Informal market scene"></p> 229<section id="informal-labour-livelihoods" class="level3"> 230<h3 data-anchor-id="informal-labour-livelihoods">Informal Labour & Livelihoods</h3> 231<p><span class="meta">How do urban residents navigate formal and informal labour markets in contexts of crisis and displacement? Mixed-methods fieldwork in Lebanon on livelihood strategies and job security in the wake of economic collapse. Funded by the Leverhulme Trust. With George Melios, Diala Makki, Yara Sleiman, and UCLâs Institute for Global Prosperity.</span></p> 232<p><a href='/informal-labour'>Learn more</a></p> 233</section> 234</div> 235<div class="media-card"> 236<p><img src="content/projects/cs.jpeg" class="img-fluid" alt="Citizen social science workshop in Lebanon"></p> 237<section id="quality-of-life-in-lebanon" class="level3"> 238<h3 data-anchor-id="quality-of-life-in-lebanon">Quality of Life in Lebanon</h3> 239<p><span class="meta">Applied participatory research on quality of life and prosperity in Lebanon, using citizen social science to co-design measurement approaches with communities in Beirut, Tripoli (El Mina), and beyond. Funded by UKRI GCRF and the Leverhulme Trust. With UCLâs Institute for Global Prosperity, the RELIEF Centre, CatalyticAction, and the American University of Beirut.</sp
239an></p> 240<p><a href="https://www.relief-centre.org/">Project Website</a></p> 241</section> 242</div> 243<div class="media-card"> 244<p><img src="content/projects/palestina.jpeg" class="img-fluid" alt="Streetscape in Ramallah, Palestine"></p> 245<section id="fipal-financial-inclusion-in-palestine" class="level3"> 246<h3 data-anchor-id="fipal-financial-inclusion-in-palestine">FiPal â Financial Inclusion in Palestine</h3> 247<p><span class="meta">Transforming financial inclusion to finance inclusive prosperity in Ramallah, Palestine. Combines participatory citizen social science with quantitative analysis of financial access, extending the Prosperity Index framework to a new setting. Funded by ESRC (2024â2026). With UCLâs Institute for Global Prosperity and Palestinian civil society partners.</span></p> 248<p><a href="https://www.ucl.ac.uk/bartlett/research-projects/2022/oct/transforming-financial-inclusion-finance-inclusive-prosperity-ramallah-palestine">Project website</a></p> 249</section> 250</div> 251</div> 252 253 254 255</main> <!-- /main -->
256<script src="assets/menu.js"></script>
vendor: 1 bytes, line 256
256
257<script id="quarto-html-after-body" type="application/javascript"> 258window.document.addEventListener("DOMContentLoaded", function (event) { 259 const toggleBodyColorMode = (bsSheetEl) => { 260 const mode = bsSheetEl.getAttribute("data-mode"); 261 const bodyEl = window.document.querySelector("body"); 262 if (mode === "dark") { 263 bodyEl.classList.add("quarto-dark"); 264 bodyEl.classList.remove("quarto-light"); 265 } else { 266 bodyEl.classList.add("quarto-light"); 267 bodyEl.classList.remove("quarto-dark"); 268 } 269 } 270 const toggleBodyColorPrimary = () => { 271 const bsSheetEl = window.document.querySelector("link#quarto-bootstrap"); 272 if (bsSheetEl) { 273 toggleBodyColorMode(bsSheetEl); 274 } 275 } 276 toggleBodyColorPrimary(); 277 const isCodeAnnotation = (el) => { 278 for (const clz of el.classList) { 279 if (clz.startsWith('code-annotation-')) { 280 return true; 281 } 282 } 283 return false; 284 } 285 const onCopySuccess = function(e) { 286 // button target 287 const button = e.trigger; 288 // don't keep focus 289 button.blur(); 290 // flash "checked" 291 button.classList.add('code-copy-button-checked'); 292 var currentTitle = button.getAttribute("title"); 293 button.setAttribute("title", "Copied!"); 294 let tooltip; 295 if (window.bootstrap) { 296 button.setAttribute("data-bs-toggle", "tooltip"); 297 button.setAttribute("data-bs-placement", "left"); 298 button.setAttribute("data-bs-title", "Copied!"); 299 tooltip = new bootstrap.Tooltip(button, 300 { trigger: "manual", 301 customClass: "code-copy-button-tooltip", 302 offset: [0, -8]}); 303 tooltip.show(); 304 } 305 setTimeout(function() { 306 if (tooltip) { 307 tooltip.hide(); 308 button.removeAttribute("data-bs-title"); 309 button.removeAttribute("data-bs-toggle"); 310 button.removeAttribute("data-bs-placement"); 311 } 312 button.setAttribute("title", currentTitle); 313 button.classList.remove('code-copy-button-checked'); 314 }, 1000); 315 // clear code selection 316 e.clearSelection(); 317 } 318 const getTextToCopy = function(trigger) { 319 const codeEl = trigger.previousElementSibling.cloneNode(true); 320 for (const childEl of codeEl.children) { 321 if (isCodeAnnotation(childEl)) { 322 childEl.remove(); 323 } 324 } 325 return codeEl.innerText; 326 } 327 const clipboard = new window.ClipboardJS('.code-copy-button:not([data-in-quarto-modal])', { 328 text: getTextToCopy 329 }); 330 clipboard.on('success', onCopySuccess); 331 if (window.document.getElementById('quarto-embedded-source-code-modal')) { 332 const clipboardModal = new window.ClipboardJS('.code-copy-button[data-in-quarto-modal]', { 333 text: getTextToCopy, 334 container: window.document.getElementById('quarto-embedded-source-code-modal') 335 }); 336 clipboardModal.on('success', onCopySuccess); 337 } 338 var localhostRegex = new RegExp(/^(?:http|https):\/\/localhost\:?[0-9]*\//); 339 var mailtoRegex = new RegExp(/^mailto:/); 340 var filterRegex = new RegExp("https:\/\/pietrostefani\.com"); 341 var isInternal = (href) => { 342 return filterRegex.test(href) || localhostRegex.test(href) || mailtoRegex.test(href); 343 } 344 // Inspect non-navigation links and adorn them if external 345 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)'); 346 for (var i=0; i<links.length; i++) { 347 const link = links[i]; 348 if (!isInternal(link.href)) { 349 // undo the damage that might have been done by quarto-nav.js in the case of 350 // links that we want to consider external 351 if (link.dataset.originalHref !== undefined) { 352 link.href = link.dataset.originalHref; 353 } 354 } 355 } 356 function tippyHover(el, contentFn, onTriggerFn, onUntriggerFn) { 357 const config = { 358 allowHTML: true, 359 maxWidth: 500, 360 delay: 100, 361 arrow: false, 362 appendTo: function(el) { 363 return el.parentElement; 364 }, 365 interactive: true, 366 interactiveBorder: 10, 367 theme: 'quarto', 368 placement: 'bottom-start', 369 }; 370 if (contentFn) { 371 config.content = contentFn; 372 } 373 if (onTriggerFn) { 374 config.onTrigger = onTriggerFn; 375 } 376 if (onUntriggerFn) { 377 config.onUntrigger = onUntriggerFn; 378 } 379 window.tippy(el, config); 380 } 381 const noterefs = window.document.querySelectorAll('a[role="doc-noteref"]'); 382 for (var i=0; i<noterefs.length; i++) { 383 const ref = noterefs[i]; 384 tippyHover(ref, function() { 385 // use id or data attribute instead here 386 let href = ref.getAttribute('data-footnote-href') || ref.getAttribute('href');
387 try { href = new URL(href).hash; } catch {} 388 const id = href.replace(/^#\/?/, ""); 389 const note = window.document.getElementById(id); 390 if (note) { 391 return note.innerHTML; 392 } else { 393 return ""; 394 } 395 }); 396 } 397 const xrefs = window.document.querySelectorAll('a.quarto-xref'); 398 const processXRef = (id, note) => { 399 // Strip column container classes 400 const stripColumnClz = (el) => { 401 el.classList.remove("page-full", "page-columns"); 402 if (el.children) { 403 for (const child of el.children) { 404 stripColumnClz(child); 405 } 406 } 407 } 408 stripColumnClz(note) 409 if (id === null || id.startsWith('sec-')) { 410 // Special case sections, only their first couple elements 411 const container = document.createElement("div"); 412 if (note.children && note.children.length > 2) { 413 container.appendChild(note.children[0].cloneNode(true)); 414 for (let i = 1; i < note.children.length; i++) { 415 const child = note.children[i]; 416 if (child.tagName === "P" && child.innerText === "") { 417 continue; 418 } else { 419 container.appendChild(child.cloneNode(true)); 420 break; 421 } 422 } 423 if (window.Quarto?.typesetMath) { 424 window.Quarto.typesetMath(container); 425 } 426 return container.innerHTML 427 } else { 428 if (window.Quarto?.typesetMath) { 429 window.Quarto.typesetMath(note); 430 } 431 return note.innerHTML; 432 } 433 } else { 434 // Remove any anchor links if they are present 435 const anchorLink = note.querySelector('a.anchorjs-link'); 436 if (anchorLink) { 437 anchorLink.remove(); 438 } 439 if (window.Quarto?.typesetMath) { 440 window.Quarto.typesetMath(note); 441 } 442 if (note.classList.contains("callout")) { 443 return note.outerHTML; 444 } else { 445 return note.innerHTML; 446 } 447 } 448 } 449 for (var i=0; i<xrefs.length; i++) { 450 const xref = xrefs[i]; 451 tippyHover(xref, undefined, function(instance) { 452 instance.disable(); 453 let url = xref.getAttribute('href'); 454 let hash = undefined; 455 if (url.startsWith('#')) { 456 hash = url; 457 } else { 458 try { hash = new URL(url).hash; } catch {} 459 } 460 if (hash) { 461 const id = hash.replace(/^#\/?/, ""); 462 const note = window.document.getElementById(id); 463 if (note !== null) { 464 try { 465 const html = processXRef(id, note.cloneNode(true)); 466 instance.setContent(html); 467 } finally { 468 instance.enable(); 469 instance.show(); 470 } 471 } else { 472 // See if we can fetch this 473 fetch(url.split('#')[0]) 474 .then(res => res.text()) 475 .then(html => { 476 const parser = new DOMParser(); 477 const htmlDoc = parser.parseFromString(html, "text/html"); 478 const note = htmlDoc.getElementById(id); 479 if (note !== null) { 480 const html = processXRef(id, note); 481 instance.setContent(html); 482 } 483 }).finally(() => { 484 instance.enable(); 485 instance.show(); 486 }); 487 } 488 } else { 489 // See if we can fetch a full url (with no hash to target) 490 // This is a special case and we should probably do some content thinning / targeting 491 fetch(url) 492 .then(res => res.text()) 493 .then(html => { 494 const parser = new DOMParser(); 495 const htmlDoc = parser.parseFromString(html, "text/html"); 496 const note = htmlDoc.querySelector('main.content'); 497 if (note !== null) { 498 // This should only happen for chapter cross references 499 // (since there is no id in the URL) 500 // remove the first header 501 if (note.children.length > 0 && note.children[0].tagName === "HEADER") { 502 note.children[0].remove(); 503 } 504 const html = processXRef(null, note); 505 instance.setContent(html); 506 } 507 }).finally(() => { 508 instance.enable(); 509 instance.show(); 510 }); 511 } 512 }, function(instance) { 513 }); 514 } 515 let selectedAnnoteEl; 516 const selectorForAnnotation = ( cell, annotation) => { 517 let cellAttr = 'data-code-cell="' + cell + '"'; 518 let lineAttr = 'data-code-annotation="' + annotation + '"'; 519 const selector = 'span[' + cellAttr + '][' + lineAttr + ']'; 520 return selector; 521 } 522 const selectCodeLines = (annoteEl) => { 523 const doc = window.document; 524 const targetCell = annoteEl.getAttribute("data-target-cell"); 525 const targetAnnotation = annoteEl.getAttribute("data-target-annotation"); 526 const annoteSpan = window.document.querySelector(selectorForAnnotation(targetCell, targetAnnotation)); 527 const lines = annoteSpan.getAttribute("data-code-lines").split(","); 528 const lineIds = lines.map((line) => { 529 return targetCell + "-" + line; 530 }) 531 let top = null; 532 let height = null; 533 let parent = null; 534 if (lineIds.length > 0) { 535 //compute the position of the single el (top and bottom and make a div) 536 const el = window.document.getElementById(lineIds[0]); 537 top = el.offsetTop; 538 height = el.offsetHeight; 539 parent = el.parentElement.parentElement; 540 if (lineIds.length > 1) { 541 const lastEl = window.document.getElementById(lineIds[lineIds.length - 1]); 542 const bottom = lastEl.offsetTop + lastEl.offsetHeight; 543 height = bottom - top; 544 } 545 if (top !== null && height !== null && parent !== null) { 546 // cook up a div (if necessary) and position it 547 let div = window.document.getElementById("code-annotation-line-highlight"); 548 if (div === null) { 549 div = window.document.createElement("div"); 550 div.setAttribute("id", "code-annotation-line-highlight"); 551 div.style.position = 'absolute'; 552 parent.appendChild(div); 553 } 554 div.style.top = top - 2 + "px"; 555 div.style.height = height + 4 + "px"; 556 div.style.left = 0; 557 let gutterDiv = window.document.getElementById("code-annotation-line-highlight-gutter"); 558 if (gutterDiv === null) { 559 gutterDiv = window.document.createElement("div"); 560 gutterDiv.setAttribute("id", "code-annotation-line-highlight-gutter"); 561 gutterDiv.style.position = 'absolute'; 562 const codeCell = window.document.getElementById(targetCell); 563 const gutter = codeCell.querySelector('.code-annotation-gutter'); 564 gutter.appendChild(gutterDiv); 565 } 566 gutterDiv.style.top = top - 2 + "px"; 567 gutterDiv.style.height = height + 4 + "px"; 568 } 569 selectedAnnoteEl = annoteEl; 570 } 571 }; 572 const unselectCodeLines = () => { 573 const elementsIds = ["code-annotation-line-highlight", "code-annotation-line-highlight-gutter"]; 574 elementsIds.forEach((elId) => { 575 const div = window.document.getElementById(elId); 576 if (div) { 577 div.remove(); 578 } 579 }); 580 selectedAnnoteEl = undefined; 581 }; 582 // Handle positioning of the toggle 583 window.addEventListener( 584 "resize", 585 throttle(() => { 586 elRect = undefined; 587 if (selectedAnnoteEl) { 588 selectCodeLines(selectedAnnoteEl); 589 } 590 }, 10) 591 ); 592 function throttle(fn, ms) { 593 let throttle = false;
594 let timer; 595 return (...args) => { 596 if(!throttle) { // first call gets through 597 fn.apply(this, args); 598 throttle = true; 599 } else { // all the others get throttled 600 if(timer) clearTimeout(timer); // cancel #2 601 timer = setTimeout(() => { 602 fn.apply(this, args); 603 timer = throttle = false; 604 }, ms); 605 } 606 }; 607 } 608 // Attach click handler to the DT 609 const annoteDls = window.document.querySelectorAll('dt[data-target-cell]'); 610 for (const annoteDlNode of annoteDls) { 611 annoteDlNode.addEventListener('click', (event) => { 612 const clickedEl = event.target; 613 if (clickedEl !== selectedAnnoteEl) { 614 unselectCodeLines(); 615 const activeEl = window.document.querySelector('dt[data-target-cell].code-annotation-active'); 616 if (activeEl) { 617 activeEl.classList.remove('code-annotation-active'); 618 } 619 selectCodeLines(clickedEl); 620 clickedEl.classList.add('code-annotation-active'); 621 } else { 622 // Unselect the line 623 unselectCodeLines(); 624 clickedEl.classList.remove('code-annotation-active'); 625 } 626 }); 627 } 628 const findCites = (el) => { 629 const parentEl = el.parentElement; 630 if (parentEl) { 631 const cites = parentEl.dataset.cites; 632 if (cites) { 633 return { 634 el, 635 cites: cites.split(' ') 636 }; 637 } else { 638 return findCites(el.parentElement) 639 } 640 } else { 641 return undefined; 642 } 643 }; 644 var bibliorefs = window.document.querySelectorAll('a[role="doc-biblioref"]'); 645 for (var i=0; i<bibliorefs.length; i++) { 646 const ref = bibliorefs[i]; 647 const citeInfo = findCites(ref); 648 if (citeInfo) { 649 tippyHover(citeInfo.el, function() { 650 var popup = window.document.createElement('div'); 651 citeInfo.cites.forEach(function(cite) { 652 var citeDiv = window.document.createElement('div'); 653 citeDiv.classList.add('hanging-indent'); 654 citeDiv.classList.add('csl-entry'); 655 var biblioDiv = window.document.getElementById('ref-' + cite); 656 if (biblioDiv) { 657 citeDiv.innerHTML = biblioDiv.innerHTML; 658 } 659 popup.appendChild(citeDiv); 660 }); 661 return popup.innerHTML; 662 }); 663 } 664 } 665}); 666</script>
666 667</div> <!-- /content --> 668<footer class="footer"> 669 <div class="nav-footer"> 670 <div class="nav-footer-left"> 671<p>© 2026 Elisabetta Pietrostefani</p> 672</div> 673 <div class="nav-footer-center"> 674 675 </div> 676 <div class="nav-footer-right"> 677<p><i class="bi bi-code-slash" aria-hidden="true"></i> Built with Quarto</p> 678</div> 679 </div> 680</footer> 681 682 683 684
685<script src="site_libs/quarto-html/zenscroll-min.js"></script>
685 686</body></html>
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.