PageSourceSearch

https://drb-workshops-portfolio.netlify.app/

html drb-workshops-portfolio.netlify.app collected 2026-10-03 10:39:53 UTC 69,683 bytes, 1,083 lines download raw bytes

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.40">
6
7<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
8
9<meta name="author" content="Biagio Palese">
10
11<title>Intro to Data Viz in R – Workshops portfolio</title>
12<style>
13code{white-space: pre-wrap;}
14span.smallcaps{font-variant: small-caps;}
15div.columns{display: flex; gap: min(4vw, 1.5em);}
16div.column{flex: auto; overflow-x: auto;}
17div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;}
18ul.task-list{list-style: none;}
19ul.task-list li input[type="checkbox"] {
20  width: 0.8em;
21  margin: 0 0.8em 0.2em -1em; /* quarto-specific, see https://github.com/quarto-dev/quarto-cli/issues/4556 */ 
22  vertical-align: middle;
23}
24</style>
25
26
27<script src="site_libs/quarto-nav/quarto-nav.js"></script>
vendor: 1 bytes, line 27
27
28<script src="site_libs/quarto-nav/headroom.min.js"></script>
vendor: 1 bytes, line 28
28
29<script src="site_libs/clipboard/clipboard.min.js"></script>
vendor: 1 bytes, line 29
29
30<script src="site_libs/quarto-search/autocomplete.umd.js"></script>
vendor: 1 bytes, line 30
30
31<script src="site_libs/quarto-search/fuse.min.js"></script>
vendor: 1 bytes, line 31
31
32<script src="site_libs/quarto-search/quarto-search.js"></script>
32
33<meta name="quarto:offset" content="./">
34<script src="site_libs/quarto-html/quarto.js"></script>
vendor: 1 bytes, line 34
34
35<script src="site_libs/quarto-html/popper.min.js"></script>
vendor: 1 bytes, line 35
35
36<script src="site_libs/quarto-html/tippy.umd.min.js"></script>
vendor: 1 bytes, line 36
36
37<script src="site_libs/quarto-html/anchor.min.js"></script>
37
38<link href="site_libs/quarto-html/tippy.css" rel="stylesheet">
39<link href="site_libs/quarto-html/quarto-syntax-highlighting-549806ee2085284f45b00abea8c6df48.css" rel="stylesheet" id="quarto-text-highlighting-styles">
40<script src="site_libs/bootstrap/bootstrap.min.js"></script>
40
41<link href="site_libs/bootstrap/bootstrap-icons.css" rel="stylesheet">
42<link href="site_libs/bootstrap/bootstrap-06d8547008b8703a04e10d11caa4a571.min.css" rel="stylesheet" append-hash="true" id="quarto-bootstrap" data-mode="light">
43<script src="site_libs/quarto-contrib/live-runtime/live-runtime.js" type="module"></script>
43
44<link href="site_libs/quarto-contrib/live-runtime/live-runtime.css" rel="stylesheet">
45<script id="quarto-search-options" type="application/json">{
46  "location": "navbar",
47  "copy-button": false,
48  "collapse-after": 3,
49  "panel-placement": "end",
50  "type": "overlay",
51  "limit": 50,
52  "keyboard-shortcut": [
53    "f",
54    "/",
55    "s"
56  ],
57  "show-item-context": false,
58  "language": {
59    "search-no-results-text": "No results",
60    "search-matching-documents-text": "matching documents",
61    "search-copy-link-title": "Copy link to search",
62    "search-hide-matches-text": "Hide additional matches",
63    "search-more-match-text": "more match in this document",
64    "search-more-matches-text": "more matches in this document",
65    "search-clear-button-title": "Clear",
66    "search-text-placeholder": "",
67    "search-detached-cancel-button-title": "Cancel",
68    "search-submit-button-title": "Submit",
69    "search-label": "Search"
70  }
71}</script>
vendor: 1 bytes, line 71
71
72<script type="module" src="site_libs/quarto-ojs/quarto-ojs-runtime.js"></script>
72
73<link href="site_libs/quarto-ojs/quarto-ojs.css" rel="stylesheet">
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="./index.html">
86    <span class="navbar-title">Workshops portfolio</span>
87    </a>
88  </div>
89          <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(); }">
90  <span class="navbar-toggler-icon"></span>
91</button>
92          <div class="collapse navbar-collapse" id="navbarCollapse">
93            <ul class="navbar-nav navbar-nav-scroll me-auto">
94  <li class="nav-item">
95    <a class="nav-link active" href="./index.html" aria-current="page"> 
96<span class="menu-text">Basic Data Viz Demo</span></a>
97  </li>  
98</ul>
99            <ul class="navbar-nav navbar-nav-scroll ms-auto">
100  <li class="nav-item">
101    <a class="nav-link" href="https://biagio-palese.netlify.app"> 
102<span class="menu-text">Back to the Dr.&nbsp;B Website</span></a>
103  </li>  
104</ul>
105          </div> <!-- /navcollapse -->
106            <div class="quarto-navbar-tools">
107</div>
108      </div> <!-- /container-fluid -->
109    </nav>
110</header>
111<!-- content -->
112<div id="quarto-content" class="quarto-container page-columns page-rows-contents page-layout-article page-navbar">
113<!-- sidebar -->
114<!-- margin-sidebar -->
115    
116<!-- main -->
117<main class="content" id="quarto-document-content">
118
119<header id="title-block-header" class="quarto-title-block default">
120<div class="quarto-title">
121<h1 class="title">Intro to Data Viz in R</h1>
122</div>
123
124
125
126<div class="quarto-title-meta">
127
128    <div>
129    <div class="quarto-title-meta-heading">Author</div>
130    <div class="quarto-title-meta-contents">
131             <p>Biagio Palese </p>
132          </div>
133  </div>
134    
135  
136    
137  </div>
138  
139
140
141</header>
142
143
144<style>
145/* Target the first tab (Demo) */
146.nav-pills .nav-item:nth-child(1) .nav-link {
147  background-color: #FFC20A; /* Yellow */
148  color: white;
149}
150
151/* Target the second tab (Example) */
152.nav-pills .nav-item:nth-child(2) .nav-link {
153  background-color: #5D3A9B; /* Purple */
154  color: white;
155}
156
157/* Target the third tab (Exercise) */
158.nav-pills .nav-item:nth-child(3) .nav-link {
159  background-color: #0C7BDC; /* Blue */
160  color: white;
161}
162
163/* Target the fourth tab (Activity) */
164.nav-pills .nav-item:nth-child(4) .nav-link {
165  background-color: #E66100; /* Orange */
166  color: white;
167}
168
169/* Target the fifth tab (Activity2) */
170.nav-pills .nav-item:nth-child(5) .nav-link {
171  background-color: #40B0A6; /* teal */
172  color: white;
173}
174
175/* Active tab styling */
176.nav-pills .nav-link.active {
177  background-color: #2E7D32; /* Customize active tab color */
178  color: white;
179}
180</style>
181<section id="welcome-to-the-magic-world-of-ggplot2" class="level2">
182<h2 class="anchored" data-anchor-id="welcome-to-the-magic-world-of-ggplot2">Welcome to the Magic World of ggplot2</h2>
183<div class="quarto-figure quarto-figure-left">
184<figure class="figure">
185<p><img src="images/ggplot2.png" class="img-fluid figure-img" width="700"></p>
186<figcaption>It’s ggplot time: Artwork by <span class="citation" data-cites="allison_horst">@allison_horst</span></figcaption>
187</figure>
188</div>
189<p>In this workshop, we’ll focus on the <code>ggplot2</code> package, a cornerstone of the <code>tidyverse</code> package. With ggplot2, we can turn raw numbers into compelling visual stories, effortlessly communicating complex data. Whether we’re examining distributions, relationships, rankings, or trends over time, visualization helps us see what the data is truly saying.</p>
190<p>Throughout this workshop, I’ll use the terms chart, plot, and graph interchangeably. While they may take different forms, they all share the same purpose: transforming data into something meaningful and impactful.</p>
191</section>
192<section id="load-packages" class="level2">
193<h2 class="anchored" data-anchor-id="load-packages">Load packages</h2>
194<p>This is a critical task:</p>
195<ul>
196<li><p>Every time you open a new R session you will need to load the packages.</p></li>
197<li><p>Failing to do so will incur in the most common errors among beginners (e.g., ” could not find function ‘x’ ” or “object ‘y’ not found”
197).</p></li>
198<li><p>So please always remember to load your packages by running the <code>library</code> function for each package you will use in that specific session 🤝</p></li>
199</ul>
200<div class="cell" data-autorun="false" data-startover="false">
201<div>
202<div id="webr-1" class="exercise-cell">
203
204</div>
205<script type="webr-1-contents">
206eyJhdHRyIjp7ImF1dG9ydW4iOmZhbHNlLCJlZGl0Ijp0cnVlLCJldmFsIjp0cnVlLCJzdGFydG92ZXIiOmZhbHNlfSwiY29kZSI6ImxpYnJhcnkodGlkeXZlcnNlKSJ9
207</script>
207
208</div>
209</div>
210<p>We will use the <code>mpg</code> data frame available in the <code>ggplot2</code> package. ggplot2 is always loaded if you load the <code>tidyverse</code> package.</p>
211<p>What is the first step when you start working with a new dataset?</p>
212</section>
213<section id="getting-to-know-the-data" class="level2">
214<h2 class="anchored" data-anchor-id="getting-to-know-the-data">Getting to know the data</h2>
215<div class="cell" data-autorun="false" data-completion="true" data-min-lines="3">
216<div>
217<div id="webr-2" class="exercise-cell">
218
219</div>
220<script type="webr-2-contents">
221eyJhdHRyIjp7ImF1dG9ydW4iOmZhbHNlLCJjb21wbGV0aW9uIjp0cnVlLCJlZGl0Ijp0cnVlLCJldmFsIjp0cnVlLCJtaW4tbGluZXMiOjN9LCJjb2RlIjoibXBnXG4/bXBnI2Rpc3BsLCBhIGNhcuKAmXMgZW5naW5lIHNpemUsIGluIGxpdHJlcy5od3ksIGEgY2Fy4oCZcyBmdWVsIGVmZmljaWVuY3kgb24gdGhlIGhpZ2h3YXksIGluIG1pbGVzIHBlciBnYWxsb24gKG1wZykifQ==
222</script>
222
223</div>
224</div>
225<p>It is also possible to get more info about the dataset by running the below code:</p>
226<div class="cell" data-autorun="false" data-completion="true" data-min-lines="3">
227<div>
228<div id="webr-3" class="exercise-cell">
229
230</div>
231<script type="webr-3-contents">
232eyJhdHRyIjp7ImF1dG9ydW4iOmZhbHNlLCJjb21wbGV0aW9uIjp0cnVlLCJlZGl0Ijp0cnVlLCJldmFsIjp0cnVlLCJtaW4tbGluZXMiOjN9LCJjb2RlIjoibXBnIHw+IGdsaW1wc2UoKVxubXBnIHw+IHN0cigpXG5tcGcgfD4gcHJpbnQod2lkdGggPSBJbmYpXG5jb2xuYW1lcyhtcGcpIn0=
233</script>
233
234</div>
235</div>
236<p>Now that we got to know the data more it is time to begin our exploratory analysis using visualizations!!!</p>
237</section>
238<section id="creating-your-first-ggplot-chart" class="level2">
239<h2 class="anchored" data-anchor-id="creating-your-first-ggplot-chart">Creating your first ggplot chart</h2>
240<p>Creating a data visualization with ggplot2 is a lot like painting. You start with a blank canvas, and just like an artist, you add layers one step at a time until the picture takes shape. At first, there’s nothing there but potential.. a canvas waiting to be filled.</p>
241<p>Each step in the process, whether it’s deciding on the chart type or choosing the colors and elements, is like adding layers of paint to a canvas. You gradually build up details, adding depth and clarity to your creation. Just as a painter chooses which areas to highlight or leave in shadow, we use tools in ggplot to emphasize different aspects of the data.</p>
242<p>By the end, what started as a blank space becomes a visual story—a piece of art that not only looks good but also communicates meaning, helping others understand the data in a way that numbers alone can’t. Enough with the theory.. let’s see how ggplot2 works in practice:</p>
243<div class="quarto-figure quarto-figure-left">
244<figure class="figure">
245<p><img src="images/ggplot1.png" class="img-fluid figure-img" width="700"></p>
246<figcaption>Ggplot in action: Artwork by <span class="citation" data-cites="allison_horst">@allison_horst</span></figcaption>
247</figure>
248</div>
249<p>With ggplot2, you always begin your plot with:</p>
250<div class="tabset-margin-container"></div><div class="panel-tabset nav-pills">
251<ul class="nav nav-tabs" role="tablist"><li class="nav-item" role="presentation"><a class="nav-link active" id="tabset-1-1-tab" data-bs-toggle="tab" data-bs-target="#tabset-1-1" role="tab" aria-controls="tabset-1-1" aria-selected="true">Blank canvas</a></li><li class="nav-item" role="presentation"><a class="nav-link" id="tabset-1-2-tab" data-bs-toggle="tab" data-bs-target="#tabset-1-2" role="tab" aria-controls="tabset-1-2" aria-selected="false">Add the data</a></li><li class="nav-item" role="presentation"><a class="nav-link" id="tabset-1-3-tab" data-bs-toggle="tab" data-bs-target="#tabset-1-3" role="tab" aria-controls="tabset-1-3" aria-selected="false">Add the axes</a></li><li class="nav-item" role="presentation"><a class="nav-link" id="tabset-1-4-tab" data-bs-toggle="tab" data-bs-target="#tabset-1-4" role="tab" aria-controls="tabset-1-4" aria-selected="false">Add the geom</a></li></ul>
252<div class="tab-content nav-pills">
253<div id="tabset-1-1" class="tab-pane active" role="tabpanel" aria-labelledby="tabset-1-1-tab">
254<div class="cell" data-autorun="false" data-completion="true" data-min-lines="3">
255<div>
256<div id="webr-4" class="exercise-cell">
257
258</div>
259<script type="webr-4-contents">
260eyJhdHRyIjp7ImF1dG9ydW4iOmZhbHNlLCJjb21wbGV0aW9uIjp0cnVlLCJlZGl0Ijp0cnVlLCJldmFsIjp0cnVlLCJtaW4tbGluZXMiOjN9LCJjb2RlIjoiZ2dwbG90KCkgIn0=
261</script>
261
262</div>
263</div>
264<ul>
265<li>the function ggplot() creates a coordinate system, your empty canvas, that you can add layers to.</li>
266</ul>
267</div>
268<div id="tabset-1-2" class="tab-pane" role="tabpanel" aria-labelledby="tabset-1-2-tab">
269<div class="cell" data-autorun="false" data-completion="true" data-min-lines="3">
270<div>
271<div id="webr-5" class="exercise-cell">
272
273</div>
274<script type="webr-5-contents">
275eyJhdHRyIjp7ImF1dG9ydW4iOmZhbHNlLCJjb21wbGV0aW9uIjp0cnVlLCJlZGl0Ijp0cnVlLCJldmFsIjp0cnVlLCJtaW4tbGluZXMiOjN9LCJjb2RlIjoiZ2dwbG90KGRhdGEgPSBtcGcpIn0=
276</script>
276
277</div>
278</div>
279<ul>
280<li>the first argument we add to our ggplot() chart is the dataset to use in the graph. While the chart is still empty now the data are loaded in the background and ready to be visualized.</li>
281</ul>
282</div>
283<div id="tabset-1-3" class="tab-pane" role="tabpanel" aria-labelledby="tabset-1-3-tab">
284<div class="cell" data-autorun="false" data-completion="true" data-min-lines="3">
285<div>
286<div id="webr-6" class="exercise-cell">
287
288</div>
289<script type="webr-6-contents">
290eyJhdHRyIjp7ImF1dG9ydW4iOmZhbHNlLCJjb21wbGV0aW9uIjp0cnVlLCJlZGl0Ijp0cnVlLCJldmFsIjp0cnVlLCJtaW4tbGluZXMiOjN9LCJjb2RlIjoiZ2dwbG90KGRhdGEgPSBtcGcsIG1hcHBpbmc9IGFlcyh5PW1hbnVmYWN0dXJlcikpIn0=
291</script>
291
292</div>
293</div>
294<ul>
295<li>then we need to map what variables we want to visualize on our axes. So ggplot(data = mpg, mapping= aes(y=manufacturer)). While the chart core of the chart is still empty, now the axes and their scales are visible.</li>
296</ul>
297</div>
298<div id="tabset-1-4" class="tab-pane" role="tabpanel" aria-labelledby="tabset-1-4-tab">
299<div class="cell" data-autorun="false" data-completion="true" data-min-lines="3">
300<div>
301<div id="webr-7" class="exercise-cell">
302
303</div>
304<script type="webr-7-contents">
305eyJhdHRyIjp7ImF1dG9ydW4iOmZhbHNlLCJjb21wbGV0aW9uIjp0cnVlLCJlZGl0Ijp0cnVlLCJldmFsIjp0cnVlLCJtaW4tbGluZXMiOjN9LCJjb2RlIjoiZ2dwbG90KGRhdGEgPSBtcGcsIG1hcHBpbmc9IGFlcyh5PW1hbnVmYWN0dXJlcikpK1xuICBnZW9tX2JhcigpIn0=
306</script>
306
307</div>
308</div>
309<ul>
310<li>The graph takes shape by choosing the type of chart you want to create. In this layer, we add the geom (short for geometric object or representation), which determines the visual structure/shape of the chart. For example, using geom_bar() adds a layer of bars, creating a bar plot. While geom_point() adds a layer of points to your plot, which creates a scatterplot.</li>
311</ul>
312</div>
313</div>
314</div>
315<p>Let’s create a few more charts to visually explore our new dataset:</p>
316<div class="tabset-margin-container"></div><div class="panel-tabset nav-pills">
317<ul class="nav nav-tabs" role="tablist"><li class="nav-item" role="presentation"><a class="nav-link active" id="tabset-2-1-tab" data-bs-toggle="tab" data-bs-target="#tabset-2-1" role="tab" aria-controls="tabset-2-1" aria-selected="true">Example 1</a></li><li class="nav-item" role="presentation"><a class="nav-link" id="tabset-2-2-tab" data-bs-toggle="tab" data-bs-target="#tabset-2-2" role="tab" aria-controls="tabset-2-2" aria-selected="false">Example 2</a></li><li class="nav-item" role="presentation"><a class="nav-link" id="tabset-2-3-tab" data-bs-toggle="tab" data-bs-target="#tabset-2-3" role="tab" aria-controls="tabset-2-3" aria-selected="false">Example 3</a></li><li class="nav-item" role="presentation"><a class="nav-link" id="tabset-2-4-tab" data-bs-toggle="tab" data-bs-target="#tabset-2-4" role="tab" aria-controls="tabset-2-4" aria-selected="false">Example 4</a></li></ul>
318<div class="tab-content nav-pills">
319<div id="tabset-2-1" class="tab-pane active" role="tabpanel" aria-labelledby="tabset-2-1-tab">
320<p>Let’s now check the distribution of highway fuel efficiency among the cars in this dataset:</p>
321<div class="cell" data-autorun="false" data-completion="true" data-min-lines="3">
322<div>
323<div id="webr-8" class="exercise-cell">
324
325</div>
326<script type="webr-8-contents">
327eyJhdHRyIjp7ImF1dG9ydW4iOmZhbHNlLCJjb21wbGV0aW9uIjp0cnVlLCJlZGl0Ijp0cnVlLCJldmFsIjp0cnVlLCJtaW4tbGluZXMiOjN9LCJjb2RlIjoiZ2dwbG90KGRhdGEgPSBtcGcsIG1hcHBpbmcgPSBhZXMoeCA9IGh3eSkpICsgXG4gIGdlb21faGlzdG9ncmFtKCkifQ==
328</script>
328
329</div>
330</div>
331<div class="callout callout-style-default callout-note callout-titled">
332<div class="callout-header d-flex align-content-center">
333<div class="callout-icon-container">
334<i class="callout-icon"></i>
335</div>
336<div class="callout-title-container flex-fill">
337Note
338</div>
339</div>
340<div class="callout-body-container callout-body">
341<p>Notice that I have used geom_histogram and not geom_bar in this case. We will learn more about which chart is the most appropriate given the column data type later in this class.</p>
342</div>
343</div>
344</div>
345<div id="tabset-2-2" class="tab-pane" role="tabpanel" aria-labelledby="tabset-2-2-tab">
346<p>Let’s now check the relation between engine size and highway fuel efficiency. Any surprise?</p>
347<div class="cell" data-autorun="false" data-completion="true" data-min-lines="3">
348<div>
349<div id="webr-9" class="exercise-cell">
350
351</div>
352<script type="webr-9-contents">
353eyJhdHRyIjp7ImF1dG9ydW4iOmZhbHNlLCJjb21wbGV0aW9uIjp0cnVlLCJlZGl0Ijp0cnVlLCJldmFsIjp0cnVlLCJtaW4tbGluZXMiOjN9LCJjb2RlIjoiXG5nZ3Bsb3QoZGF0YSA9IG1wZywgbWFwcGluZyA9IGFlcyh4ID0gZGlzcGwsIHkgPSBod3kpKSArIFxuICBnZW9tX3BvaW50KCkifQ==
354</script>
354
355</div>
356</div>
357<p>Cars with big engines seem to use more fuel. But… there are a small number of cars with large engine that still have pretty good highway fuel efficiency.</p>
358</div>
359<div id="tabset-2-3" class="tab-pane" role="tabpanel" aria-labelledby="tabset-2-3-tab">
360<p>Create a histogram chart that show the distribution of the city fuel efficiency (cty) variable</p>
361<div class="cell" data-autorun="false" data-completion="true" data-min-lines="3">
362<div>
363<div id="webr-10" class="exercise-cell">
364
365</div>
366<script type="webr-10-contents">
367eyJhdHRyIjp7ImF1dG9ydW4iOmZhbHNlLCJjb21wbGV0aW9uIjp0cnVlLCJlZGl0Ijp0cnVlLCJldmFsIjp0cnVlLCJtaW4tbGluZXMiOjN9LCJjb2RlIjoiIn0=
368</script>
368
369</div>
370</div>
371</div>
372<div id="tabset-2-4" class="tab-pane" role="tabpanel" aria-labelledby="tabset-2-4-tab">
373<p>Create a scatterplot that shows the relationship between engine size and city fuel efficiency</p>
374<div class="cell" data-autorun="false" data-completion="true" data-min-lines="3">
375<div>
376<div id="webr-11" class="exercise-cell">
377
378</div>
379<script type="webr-11-contents">
380eyJhdHRyIjp7ImF1dG9ydW4iOmZhbHNlLCJjb21wbGV0aW9uIjp0cnVlLCJlZGl0Ijp0cnVlLCJldmFsIjp0cnVlLCJtaW4tbGluZXMiOjN9LCJjb2RlIjoiIn0=
381</script>
381
382</div>
383</div>
384</div>
385</div>
386</div>
387<section id="activity-1-a-b-in-class-c-d-at-home-basic-charts---5-minutes" class="level4">
388<h4 class="anchored">Activity 1 (a &amp; b in class c &amp; d at home): Basic Charts - 5 minutes:</h4>
389<p><em>[Write code just below each instruction; finally use MS Teams R - Forum channel for help on the in class activities/homework or if you have other questions]</em></p>
390<div class="tabset-margin-container"></div><div class="panel-tabset nav-pills">
391<ul class="nav nav-tabs" role="tablist"><li class="nav-item" role="presentation"><a class="nav-link active" id="tabset-3-1-tab" data-bs-toggle="tab" data-bs-target="#tabset-3-1" role="tab" aria-controls="tabset-3-1" aria-selected="true">Activity 1a.</a></li><li class="nav-item" role="presentation"><a class="nav-link" id="tabset-3-2-tab" data-bs-toggle="tab" data-bs-target="#tabset-3-2" role="tab" aria-controls="tabset-3-2" aria-selected="false">Activity 1b.</a></li><li class="nav-item" role="presentation"><a class="nav-link" id="tabset-3-3-tab" data-bs-toggle="tab" data-bs-target="#tabset-3-3" role="tab" aria-controls="tabset-3-3" aria-selected="false">Activity 1c.</a></li><li class="nav-item" role="presentation"><a class="nav-link" id="tabset-3-4-tab" data-bs-toggle="tab" data-bs-target="#tabset-3-4" role="tab" aria-controls="tabset-3-4" aria-selected="false">Activity 1d.</a></li></ul>
392<div class="tab-content nav-pills">
393<div id="tabset-3-1" class="tab-pane active" role="tabpanel" aria-labelledby="tabset-3-1-tab">
394<p>Create a bar chart for the <code>class</code> variable.</p>
395<div class="cell" data-autorun="false" data-completion="true" data-min-lines="3">
396<div>
397<div id="webr-12" class="exercise-cell">
398
399</div>
400<script type="webr-12-contents">
401eyJhdHRyIjp7ImF1dG9ydW4iOmZhbHNlLCJjb21wbGV0aW9uIjp0cnVlLCJlZGl0Ijp0cnVlLCJldmFsIjp0cnVlLCJtaW4tbGluZXMiOjN9LCJjb2RlIjoiZ2dwbG90KGRhdGE9bXBnLCBtYXBwaW5nPSBhZXMoeD0gY2xhc3MpKStcbiAgZ2VvbV9iYXIoKSJ9
402</script>
402
403</div>
404</div>
405</div>
406<div id="tabset-3-2" class="tab-pane" role="tabpanel" aria-labelledby="tabset-3-2-tab">
407<p>Create a scatterplot between the highway fuel efficiency and number of cylinders.</p>
408<div class="cell" data-autorun="false" data-completion="true" data-min-lines="3">
409<div>
410<div id="webr-13" class="exercise-cell">
411
412</div>
413<script type="webr-13-contents">
414eyJhdHRyIjp7ImF1dG9ydW4iOmZhbHNlLCJjb21wbGV0aW9uIjp0cnVlLCJlZGl0Ijp0cnVlLCJldmFsIjp0cnVlLCJtaW4tbGluZXMiOjN9LCJjb2RlIjoiZ2dwbG90KGRhdGE9bXBnLCBtYXBwaW5nPSBhZXMoeD0gY3lsLCB5PWh3eSkpK1xuICBnZW9tX3BvaW50KCkifQ==
415</script>
415
416</div>
417</div>
418<p>What do you notice?</p>
419</div>
420<div id="tabset-3-3" class="tab-pane" role="tabpanel" aria-labelledby="tabset-3-3-tab">
421<p>Create a boxplot that show the distribution of the city fuel efficiency (cty) variable.</p>
422<div class="cell" data-autorun="false" data-completion="true" data-min-lines="3">
423<div>
424<div id="webr-14" class="exercise-cell">
425
426</div>
427<script type="webr-14-contents">
428eyJhdHRyIjp7ImF1dG9ydW4iOmZhbHNlLCJjb21wbGV0aW9uIjp0cnVlLCJlZGl0Ijp0cnVlLCJldmFsIjp0cnVlLCJtaW4tbGluZXMiOjN9LCJjb2RlIjoiZ2dwbG90KGRhdGE9bXBnLCBtYXBwaW5nPSBhZXMoeT0gY3R5KSkrXG4gIGdlb21fYm94cGxvdCgpIn0=
429</script>
429
430</div>
431</div>
432</div>
433<div id="tabset-3-4" class="tab-pane" role="tabpanel" aria-labelledby="tabset-3-4-tab">
434<p>Create a bar chart for the <code>fl</code> variable.</p>
435<div class="cell" data-autorun="false" data-completion="true" data-min-lines="3">
436<div>
437<div id="webr-15" class="exercise-cell">
438
439</div>
440<script type="webr-15-contents">
441eyJhdHRyIjp7ImF1dG9ydW4iOmZhbHNlLCJjb21wbGV0aW9uIjp0cnVlLCJlZGl0Ijp0cnVlLCJldmFsIjp0cnVlLCJtaW4tbGluZXMiOjN9LCJjb2RlIjoiZ2dwbG90KGRhdGE9bXBnLCBtYXBwaW5nPSBhZXMoeD0gZmwpKStcbiAgZ2VvbV9iYXIoKSJ9
442</script>
442
443</div>
444</div>
445</div>
446</div>
447</div>
448<div class="cell" data-autorun="false" data-min-lines="3">
449<div>
450<div id="webr-16" class="exercise-cell">
451
452</div>
453<script type="webr-16-contents">
454eyJhdHRyIjp7ImF1dG9ydW4iOmZhbHNlLCJlZGl0Ijp0cnVlLCJldmFsIjp0cnVlLCJtaW4tbGluZXMiOjN9LCJjb2RlIjoiXG5cbiNDb2RlIFByYWN0aWNlIENodW5rIn0=
455</script>
455
456</div>
457</div>
458<p><em>Knowledge Check 1</em></p>
459<div class="quarto-figure quarto-figure-center">
460<figure class="figure">
461<p><img src="images/knowledgecheck1.png" class="img-fluid figure-img"></p>
462<figcaption>Figure 2. Knowledge Check 1</figcaption>
463</figure>
464</div>
465<p>Question: What geom was used in the chart above?</p>
466<pre><code>- answer 1: geom_bar,
467- answer 2: geom_point,
468- answer 3: geom_boxplot,
469- answer 4: geom_plot</code></pre>
470<div class="callout callout-style-default callout-important callout-titled">
471<div class="callout-header d-flex align-content-center">
472<div class="callout-icon-container">
473<i class="callout-icon"></i>
474</div>
475<div class="callout-title-container flex-fill">
476Important
477</div>
478</div>
479<div class="callout-body-container callout-body">
480<p>Please remember that this is just a demo of the workshop I run and their style. If you or your company want more info about the workshop do not hesitate to click on the Get in Touch button.</p>
481</div>
482</div>
483<button id="contact-button" class="open-button">
484Get in Touch
485</button>
486<div id="contact-form" class="form-popup">
487<form class='form-container' method='POST' name='contact-workshop'>
488<h2 class="anchored" data-anchor-id="activity-1-a-b-in-class-c-d-at-home-basic-charts---5-minutes">
489Contact Me
490</h2>
491<input type="hidden" name="form-name" value="contact-workshop"> <input type="text" placeholder="Name" name="name" required=""> <input type="email" placeholder="Email" name="email" required="">
492<textarea placeholder="Message" name="message" required=""></textarea>
493<button type="submit" class="btn">
494Send
495</button>
496<button type="button" class="btn cancel" onclick="closeForm()">
497Close
498</button>
499</form>
500</div>
501<style>
502.open-button {
503  background-color: #555;
504  color: white;
505  padding: 16px 20px;
506  border: none;
507  cursor: pointer;
508  position: fixed;
509  bottom: 23px;
510  right: 28px;
511  z-index: 9;
512}
513
514.form-popup {
515  display: none;
516  position: fixed;
517  top: 50%;
518  left: 50%;
519  transform: translate(-50%, -50%);
520  border: 3px solid #f1f1f1;
521  z-index: 10;
522  max-width: 400px;
523  width: 90%;
524}
525
526.form-container {
527  padding: 20px;
528  background-color: white;
529}
530
531.form-container input[type=text], .form-container input[type=email], .form-container textarea {
532  width: 100%;
533  padding: 12px;
534  margin: 8px 0;
535  border: 1px solid #ccc;
536  background: #f8f8f8;
537}
538
539.form-container textarea {
540  height: 100px;
541}
542
543.form-container .btn {
544  background-color: #04AA6D;
545  color: white;
546  padding: 12px 20px;
547  border: none;
548  cursor: pointer;
549  width: 100%;
550  margin-bottom: 10px;
551  opacity: 0.8;
552}
553
554.form-container .cancel {
555  background-color: #ff4d4d;
556}
557
558.form-container .btn:hover, .open-button:hover {
559  opacity: 1;
560}
561</style>
562<script>
563function openForm() {
564  document.getElementById("contact-form").style.display = "block";
565}
566
567function closeForm() {
568  document.getElementById("contact-form").style.display = "none";
569}
570
571document.addEventListener('DOMContentLoaded', function() {
572  document.getElementById("contact-button").addEventListener("click", openForm);
573});
574</script>
574
575<div class="quarto-figure quarto-figure-left">
576<figure class="figure">
577<p><img src="gif/congrats.webp" class="img-fluid figure-img" width="700"></p>
578<figcaption><strong>On completing the workshop</strong></figcaption>
579</figure>
580</div>
581<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/confetti.browser.min.js"></script>
vendor: 1 bytes, line 581
581
582<script>
583  var confettiTriggered = false;
584  var duration = 15 * 1000;
585  var animationEnd = Date.now() + duration;
586  var defaults = { startVelocity: 30, spread: 360, ticks: 60, zIndex: 0 };
587 
588  function randomInRange(min, max) {
589    return Math.random() * (max - min) + min;
590  }
591 
592  // Function to start the confetti effect
593  function startConfetti() {
594    if (!confettiTriggered) {
595      confettiTriggered = true; // Prevent confetti from starting multiple times
596      var interval = setInterval(function() {
597        var timeLeft = animationEnd - Date.now();
598 
599        if (timeLeft <= 0) {
600          clearInterval(interval); // Stop the animation when the duration ends
601        }
602 
603        var particleCount = 50 * (timeLeft / duration);
604        // Since particles fall down, start a bit higher than random
605        confetti({ 
606          ...defaults, 
607          particleCount, 
608          origin: { x: randomInRange(0.1, 0.3), y: Math.random() - 0.2 } 
609        });
610        confetti({ 
611          ...defaults, 
612          particleCount, 
613          origin: { x: randomInRange(0.7, 0.9), y: Math.random() - 0.2 } 
614        });
615      }, 250);
616    }
617  }
618 
619  // Event listener to detect when the user scrolls to the bottom of the page
620  window.addEventListener("scroll", function() {
621    // Check if the user has scrolled to the bottom of the page
622    if ((window.innerHeight + window.scrollY) >= document.body.offsetHeight) {
623      startConfetti();
624    }
625  });
626</script>
626
627
628
629<script type="webr-data">
630eyJvcHRpb25zIjp7ImJhc2VVcmwiOiJodHRwczovL3dlYnIuci13YXNtLm9yZy92MC40LjIvIn0sInBhY2thZ2VzIjp7InBrZ3MiOlsiZXZhbHVhdGUiLCJrbml0ciIsImh0bWx0b29scyIsInRpZHl2ZXJzZSIsImphbml0b3IiXSwicmVwb3MiOltdfSwicmVuZGVyX2RmIjoiZGVmYXVsdCJ9
631</script>
vendor: 1 bytes, line 631
631
632<script type="ojs-module-contents">
633eyJjb250ZW50cyI6W3siY2VsbE5hbWUiOiJ3ZWJyLXdpZGdldC0xNiIsImlubGluZSI6ZmFsc2UsIm1ldGhvZE5hbWUiOiJpbnRlcnByZXRRdWlldCIsInNvdXJjZSI6IntcbiAgLy8gV2FpdCBmb3Igb3V0cHV0IHRvIGJlIHdyaXR0ZW4gdG8gdGhlIERPTSwgdGhlbiB0cmlnZ2VyIHdpZGdldCByZW5kZXJpbmdcbiAgYXdhaXQgX3dlYnJfdmFsdWVfMTY7XG4gIGlmICh3aW5kb3cuSFRNTFdpZGdldHMpIHtcbiAgICB3aW5kb3cuSFRNTFdpZGdldHMuc3RhdGljUmVuZGVyKCk7XG4gIH1cbiAgaWYgKHdpbmRvdy5QYWdlZFRhYmxlRG9jKSB7XG4gICAgd2luZG93LlBhZ2VkVGFibGVEb2MuaW5pdEFsbCgpO1xuICB9XG59XG4ifSx7ImNlbGxOYW1lIjoid2Vici0xNiIsImlubGluZSI6ZmFsc2UsIm1ldGhvZE5hbWUiOiJpbnRlcnByZXQiLCJzb3VyY2UiOiJ2aWV3b2YgX3dlYnJfZWRpdG9yXzE2ID0ge1xuICBjb25zdCB7IFdlYlJFeGVyY2lzZUVkaXRvciwgYjY0RGVjb2RlIH0gPSB3aW5kb3cuX2V4ZXJjaXNlX29qc19ydW50aW1lO1xuICBjb25zdCBzY3JpcHRDb250ZW50ID0gZG9jdW1lbnQucXVlcnlTZWxlY3Rvcihgc2NyaXB0W3R5cGU9XFxcIndlYnItMTYtY29udGVudHNcXFwiXWApLnRleHRDb250ZW50O1xuICBjb25zdCBibG9jayA9IEpTT04ucGFyc2UoYjY0RGVjb2RlKHNjcmlwdENvbnRlbnQpKTtcblxuICBjb25zdCBvcHRpb25zID0gT2JqZWN0LmFzc2lnbih7IGlkOiBgd2Vici0xNi1jb250ZW50c2AgfSwgYmxvY2suYXR0cik7XG4gIGNvbnN0IGVkaXRvciA9IG5ldyBXZWJSRXhlcmNpc2VFZGl0b3Iod2ViUk9qcy53ZWJSUHJvbWlzZSwgYmxvY2suY29kZSwgb3B0aW9ucyk7XG5cbiAgcmV0dXJuIGVkaXRvci5jb250YWluZXI7XG59XG5fd2Vicl92YWx1ZV8xNiA9IHdlYlJPanMucHJvY2Vzcyhfd2Vicl9lZGl0b3JfMTYsIHt9KTtcbiJ9LHsiY2VsbE5hbWUiOiJ3ZWJyLXdpZGdldC0xNSIsImlubGluZSI6ZmFsc2UsIm1ldGhvZE5hbWUiOiJpbnRlcnByZXRRdWlldCIsInNvdXJjZSI6IntcbiAgLy8gV2FpdCBmb3Igb3V0cHV0IHRvIGJlIHdyaXR0ZW4gdG8gdGhlIERPTSwgdGhlbiB0cmlnZ2VyIHdpZGdldCByZW5kZXJpbmdcbiAgYXdhaXQgX3dlYnJfdmFsdWVfMTU7XG4gIGlmICh3aW5kb3cuSFRNTFdpZGdldHMpIHtcbiAgICB3aW5kb3cuSFRNTFdpZGdldHMuc3RhdGljUmVuZGVyKCk7XG4gIH1cbiAgaWYgKHdpbmRvdy5QYWdlZFRhYmxlRG9jKSB7XG4gICAgd2luZG93LlBhZ2VkVGFibGVEb2MuaW5pdEFsbCgpO1xuICB9XG59XG4ifSx7ImNlbGxOYW1lIjoid2Vici0xNSIsImlubGluZSI6ZmFsc2UsIm1ldGhvZE5hbWUiOiJpbnRlcnByZXQiLCJzb3VyY2UiOiJ2aWV3b2YgX3dlYnJfZWRpdG9yXzE1ID0ge1xuICBjb25zdCB7IFdlYlJFeGVyY2lzZUVkaXRvciwgYjY0RGVjb2RlIH0gPSB3aW5kb3cuX2V4ZXJjaXNlX29qc19ydW50aW1lO1xuICBjb25zdCBzY3JpcHRDb250ZW50ID0gZG9jdW1lbnQucXVlcnlTZWxlY3Rvcihgc2NyaXB0W3R5cGU9XFxcIndlYnItMTUtY29udGVudHNcXFwiXWApLnRleHRDb250ZW50O1xuICBjb25zdCBibG9jayA9IEpTT04ucGFyc2UoYjY0RGVjb2RlKHNjcmlwdENvbnRlbnQpKTtcblxuICBjb25zdCBvcHRpb25zID0gT2JqZWN0LmFzc2lnbih7IGlkOiBgd2Vici0xNS1jb250ZW50c2AgfSwgYmxvY2suYXR0cik7XG4gIGNvbnN0IGVkaXRvciA9IG5ldyBXZWJSRXhlcmNpc2VFZGl0b3Iod2ViUk9qcy53ZWJSUHJvbWlzZSwgYmxvY2suY29kZSwgb3B0aW9ucyk7XG5cbiAgcmV0dXJuIGVkaXRvci5jb250YWluZXI7XG59XG5fd2Vicl92YWx1ZV8xNSA9IHdlYlJPanMucHJvY2Vzcyhfd2Vicl9lZGl0b3JfMTUsIHt9KTtcbiJ9LHsiY2VsbE5hbWUiOiJ3ZWJyLXdpZGdldC0xNCIsImlubGluZSI6ZmFsc2UsIm1ldGhvZE5hbWUiOiJpbnRlcnByZXRRdWlldCIsInNvdXJjZSI6IntcbiAgLy8gV2FpdCBmb3Igb3V0cHV0IHRvIGJlIHdyaXR0ZW4gdG8gdGhlIERPTSwgdGhlbiB0cmlnZ2VyIHdpZGdldCByZW5kZXJpbmdcbiAgYXdhaXQgX3dlYnJfdmFsdWVfMTQ7XG4gIGlmICh3aW5kb3cuSFRNTFdpZGdldHMpIHtcbiAgICB3aW5kb3cuSFRNTFdpZGdldHMuc3RhdGljUmVuZGVyKCk7XG4gIH1cbiAgaWYgKHdpbmRvdy5QYWdlZFRhYmxlRG9jKSB7XG4gICAgd2luZG93LlBhZ2VkVGFibGVEb2MuaW5pdEFsbCgpO1xuICB9XG59XG4ifSx7ImNlbGxOYW1lIjoid2Vici0xNCIsImlubGluZSI6ZmFsc2UsIm1ldGhvZE5hbWUiOiJpbnRlcnByZXQiLCJzb3VyY2UiOiJ2aWV3b2YgX3dlYnJfZWRpdG9yXzE0ID0ge1xuICBjb25zdCB7IFdlYlJFeGVyY2lzZUVkaXRvciwgYjY0RGVjb2RlIH0gPSB3aW5kb3cuX2V4ZXJjaXNlX29qc19ydW50aW1lO1xuICBjb25zdCBzY3JpcHRDb250ZW50ID0gZG9jdW1lbnQucXVlcnlTZWxlY3Rvcihgc2NyaXB0W3R5cGU9XFxcIndlYnItMTQtY29udGVudHNcXFwiXWApLnRleHRDb250ZW50O1xuICBjb25zdCBibG9jayA9IEpTT04ucGFyc2UoYjY0RGVjb2RlKHNjcmlwdENvbnRlbnQpKTtcblxuICBjb25zdCBvcHRpb25zID0gT2JqZWN0LmFzc2lnbih7IGlkOiBgd2Vici0xNC1jb250ZW50c2AgfSwgYmxvY2suYXR0cik7XG4gIGNvbnN0IGVkaXRvciA9IG5ldyBXZWJSRXhlcmNpc2VFZGl0b3Iod2ViUk9qcy53ZWJSUHJvbWlzZSwgYmxvY2suY29kZSwgb3B0aW9ucyk7XG5cbiAgcmV0dXJuIGVkaXRvci5jb250YWluZXI7XG59XG5fd2Vicl92YWx1ZV8xNCA9IHdlYlJPanMucHJvY2Vzcyhfd2Vicl9lZGl0b3JfMTQsIHt9KTtcbiJ9LHsiY2VsbE5hbWUiOiJ3ZWJyLXdpZGdldC0xMyIsImlubGluZSI6ZmFsc2UsIm1ldGhvZE5hbWUiOiJpbnRlcnByZXRRdWlldCIsInNvdXJjZSI6IntcbiAgLy8gV2FpdCBmb3Igb3V0cHV0IHRvIGJlIHdyaXR0ZW4gdG8gdGhlIERPTSwgdGhlbiB0cmlnZ2VyIHdpZGdldCByZW5kZXJpbmdcbiAgYXdhaXQgX3dlYnJfdmFsdWVfMTM7XG4gIGlmICh3aW5kb3cuSFRNTFdpZGdldHMpIHtcbiAgICB3aW5kb3cuSFRNTFdpZGdldHMuc3RhdGljUmVuZGVyKCk7XG4gIH1cbiAgaWYgKHdpbmRvdy5QYWdlZFRhYmxlRG9jKSB7XG4gICAgd2luZG93LlBhZ2VkVGFibGVEb2MuaW5pdEFsbCgpO1xuICB9XG59XG4ifSx7ImNlbGxOYW1lIjoid2Vici0xMyIsImlubGluZSI6ZmFsc2UsIm1ldGhvZE5hbWUiOiJpbnRlcnByZXQiLCJzb3VyY2UiOiJ2aWV3b2YgX3dlYnJfZWRpdG9yXzEzID0ge1xuICBjb25zdCB7IFdlYlJFeGVyY2lzZUVkaXRvciwgYjY0RGVjb2RlIH0gPSB3aW5kb3cuX2V4ZXJjaXNlX29qc19ydW50aW1lO1xuICBjb25zdCBzY3JpcHRDb250ZW50ID0gZG9jdW1lbnQucXVlcnlTZWxlY3Rvcihgc2NyaXB0W3R5cGU9XFxcIndlYnItMTMtY29udGVudHNcXFwiXWApLnRleHRDb250ZW50O1xuICBjb25zdCBibG9jayA9IEpTT04ucGFyc2UoYjY0RGVjb2RlKHNjcmlwdENvb
633nRlbnQpKTtcblxuICBjb25zdCBvcHRpb25zID0gT2JqZWN0LmFzc2lnbih7IGlkOiBgd2Vici0xMy1jb250ZW50c2AgfSwgYmxvY2suYXR0cik7XG4gIGNvbnN0IGVkaXRvciA9IG5ldyBXZWJSRXhlcmNpc2VFZGl0b3Iod2ViUk9qcy53ZWJSUHJvbWlzZSwgYmxvY2suY29kZSwgb3B0aW9ucyk7XG5cbiAgcmV0dXJuIGVkaXRvci5jb250YWluZXI7XG59XG5fd2Vicl92YWx1ZV8xMyA9IHdlYlJPanMucHJvY2Vzcyhfd2Vicl9lZGl0b3JfMTMsIHt9KTtcbiJ9LHsiY2VsbE5hbWUiOiJ3ZWJyLXdpZGdldC0xMiIsImlubGluZSI6ZmFsc2UsIm1ldGhvZE5hbWUiOiJpbnRlcnByZXRRdWlldCIsInNvdXJjZSI6IntcbiAgLy8gV2FpdCBmb3Igb3V0cHV0IHRvIGJlIHdyaXR0ZW4gdG8gdGhlIERPTSwgdGhlbiB0cmlnZ2VyIHdpZGdldCByZW5kZXJpbmdcbiAgYXdhaXQgX3dlYnJfdmFsdWVfMTI7XG4gIGlmICh3aW5kb3cuSFRNTFdpZGdldHMpIHtcbiAgICB3aW5kb3cuSFRNTFdpZGdldHMuc3RhdGljUmVuZGVyKCk7XG4gIH1cbiAgaWYgKHdpbmRvdy5QYWdlZFRhYmxlRG9jKSB7XG4gICAgd2luZG93LlBhZ2VkVGFibGVEb2MuaW5pdEFsbCgpO1xuICB9XG59XG4ifSx7ImNlbGxOYW1lIjoid2Vici0xMiIsImlubGluZSI6ZmFsc2UsIm1ldGhvZE5hbWUiOiJpbnRlcnByZXQiLCJzb3VyY2UiOiJ2aWV3b2YgX3dlYnJfZWRpdG9yXzEyID0ge1xuICBjb25zdCB7IFdlYlJFeGVyY2lzZUVkaXRvciwgYjY0RGVjb2RlIH0gPSB3aW5kb3cuX2V4ZXJjaXNlX29qc19ydW50aW1lO1xuICBjb25zdCBzY3JpcHRDb250ZW50ID0gZG9jdW1lbnQucXVlcnlTZWxlY3Rvcihgc2NyaXB0W3R5cGU9XFxcIndlYnItMTItY29udGVudHNcXFwiXWApLnRleHRDb250ZW50O1xuICBjb25zdCBibG9jayA9IEpTT04ucGFyc2UoYjY0RGVjb2RlKHNjcmlwdENvbnRlbnQpKTtcblxuICBjb25zdCBvcHRpb25zID0gT2JqZWN0LmFzc2lnbih7IGlkOiBgd2Vici0xMi1jb250ZW50c2AgfSwgYmxvY2suYXR0cik7XG4gIGNvbnN0IGVkaXRvciA9IG5ldyBXZWJSRXhlcmNpc2VFZGl0b3Iod2ViUk9qcy53ZWJSUHJvbWlzZSwgYmxvY2suY29kZSwgb3B0aW9ucyk7XG5cbiAgcmV0dXJuIGVkaXRvci5jb250YWluZXI7XG59XG5fd2Vicl92YWx1ZV8xMiA9IHdlYlJPanMucHJvY2Vzcyhfd2Vicl9lZGl0b3JfMTIsIHt9KTtcbiJ9LHsiY2VsbE5hbWUiOiJ3ZWJyLXdpZGdldC0xMSIsImlubGluZSI6ZmFsc2UsIm1ldGhvZE5hbWUiOiJpbnRlcnByZXRRdWlldCIsInNvdXJjZSI6IntcbiAgLy8gV2FpdCBmb3Igb3V0cHV0IHRvIGJlIHdyaXR0ZW4gdG8gdGhlIERPTSwgdGhlbiB0cmlnZ2VyIHdpZGdldCByZW5kZXJpbmdcbiAgYXdhaXQgX3dlYnJfdmFsdWVfMTE7XG4gIGlmICh3aW5kb3cuSFRNTFdpZGdldHMpIHtcbiAgICB3aW5kb3cuSFRNTFdpZGdldHMuc3RhdGljUmVuZGVyKCk7XG4gIH1cbiAgaWYgKHdpbmRvdy5QYWdlZFRhYmxlRG9jKSB7XG4gICAgd2luZG93LlBhZ2VkVGFibGVEb2MuaW5pdEFsbCgpO1xuICB9XG59XG4ifSx7ImNlbGxOYW1lIjoid2Vici0xMSIsImlubGluZSI6ZmFsc2UsIm1ldGhvZE5hbWUiOiJpbnRlcnByZXQiLCJzb3VyY2UiOiJ2aWV3b2YgX3dlYnJfZWRpdG9yXzExID0ge1xuICBjb25zdCB7IFdlYlJFeGVyY2lzZUVkaXRvciwgYjY0RGVjb2RlIH0gPSB3aW5kb3cuX2V4ZXJjaXNlX29qc19ydW50aW1lO1xuICBjb25zdCBzY3JpcHRDb250ZW50ID0gZG9jdW1lbnQucXVlcnlTZWxlY3Rvcihgc2NyaXB0W3R5cGU9XFxcIndlYnItMTEtY29udGVudHNcXFwiXWApLnRleHRDb250ZW50O1xuICBjb25zdCBibG9jayA9IEpTT04ucGFyc2UoYjY0RGVjb2RlKHNjcmlwdENvbnRlbnQpKTtcblxuICBjb25zdCBvcHRpb25zID0gT2JqZWN0LmFzc2lnbih7IGlkOiBgd2Vici0xMS1jb250ZW50c2AgfSwgYmxvY2suYXR0cik7XG4gIGNvbnN0IGVkaXRvciA9IG5ldyBXZWJSRXhlcmNpc2VFZGl0b3Iod2ViUk9qcy53ZWJSUHJvbWlzZSwgYmxvY2suY29kZSwgb3B0aW9ucyk7XG5cbiAgcmV0dXJuIGVkaXRvci5jb250YWluZXI7XG59XG5fd2Vicl92YWx1ZV8xMSA9IHdlYlJPanMucHJvY2Vzcyhfd2Vicl9lZGl0b3JfMTEsIHt9KTtcbiJ9LHsiY2VsbE5hbWUiOiJ3ZWJyLXdpZGdldC0xMCIsImlubGluZSI6ZmFsc2UsIm1ldGhvZE5hbWUiOiJpbnRlcnByZXRRdWlldCIsInNvdXJjZSI6IntcbiAgLy8gV2FpdCBmb3Igb3V0cHV0IHRvIGJlIHdyaXR0ZW4gdG8gdGhlIERPTSwgdGhlbiB0cmlnZ2VyIHdpZGdldCByZW5kZXJpbmdcbiAgYXdhaXQgX3dlYnJfdmFsdWVfMTA7XG4gIGlmICh3aW5kb3cuSFRNTFdpZGdldHMpIHtcbiAgICB3aW5kb3cuSFRNTFdpZGdldHMuc3RhdGljUmVuZGVyKCk7XG4gIH1cbiAgaWYgKHdpbmRvdy5QYWdlZFRhYmxlRG9jKSB7XG4gICAgd2luZG93LlBhZ2VkVGFibGVEb2MuaW5pdEFsbCgpO1xuICB9XG59XG4ifSx7ImNlbGxOYW1lIjoid2Vici0xMCIsImlubGluZSI6ZmFsc2UsIm1ldGhvZE5hbWUiOiJpbnRlcnByZXQiLCJzb3VyY2UiOiJ2aWV3b2YgX3dlYnJfZWRpdG9yXzEwID0ge1xuICBjb25zdCB7IFdlYlJFeGVyY2lzZUVkaXRvciwgYjY0RGVjb2RlIH0gPSB3aW5kb3cuX2V4ZXJjaXNlX29qc19ydW50aW1lO1xuICBjb25zdCBzY3JpcHRDb250ZW50ID0gZG9jdW1lbnQucXVlcnlTZWxlY3Rvcihgc2NyaXB0W3R5cGU9XFxcIndlYnItMTAtY29udGVudHNcXFwiXWApLnRleHRDb250ZW50O1xuICBjb25zdCBibG9jayA9IEpTT04ucGFyc2UoYjY0RGVjb2RlKHNjcmlwdENvbnRlbnQpKTtcblxuICBjb25zdCBvcHRpb25zID0gT2JqZWN0LmFzc2lnbih7IGlkOiBgd2Vici0xMC1jb250ZW50c2AgfSwgYmxvY2suYXR0cik7XG4gIGNvbnN0IGVkaXRvciA9IG5ldyBXZWJSRXhlcmNpc2VFZGl0b3Iod2ViUk9qcy53ZWJSUHJvbWlzZSwgYmxvY2suY29kZSwgb3B0aW9ucyk7XG5cbiAgcmV0dXJuIGVkaXRvci5jb250YWluZXI7XG59XG5fd2Vicl92YWx1ZV8xMCA9IHdlYlJPanMucHJvY2Vzcyhfd2Vicl9lZGl0b3JfMTAsIHt9KTtcbiJ9LHsiY2VsbE5hbWUiOiJ3ZWJyLXdpZGdldC05IiwiaW5saW5lIjpmYWxzZSwibWV0aG9kTmFtZSI6ImludGVycHJldFF1aWV0Iiwic291cmNlIjoie1xuICAvLyBXYWl0IGZvciBvdXRwdXQgdG8gYmUgd3JpdHRlbiB0byB0aGUgRE9NLCB0aGVuIHRyaWdnZXIgd2lkZ2V0IHJlbmRlcmluZ1xuICBhd2FpdCBfd2Vicl92YWx1ZV85O1xuICBpZiAod2luZG93LkhUTUxXaWRnZXRzKSB7XG4gICAgd2luZG93LkhUTUxXaWRnZXRzLnN0YXRpY1JlbmRlcigpO1xuICB9XG4gIGlmICh3aW5kb3cuUGFnZWRUYWJsZURvYykge1xuICAgIHdpbmRvdy5QYWdlZFRhYmxlRG9jLmluaXRBbGwoKTtcbiAgfVxufVxuIn0seyJjZWxsTmFtZSI6IndlYnItOSIsImlubGluZSI6ZmFsc2UsIm1ldGhvZE5hbWUiOiJpbnRlcnByZXQiLCJzb3VyY2UiOiJ2aWV3b2YgX3dlYnJfZWRpdG9yXzkgPSB7XG4gIGNvbnN0IHsgV2ViUkV4ZXJjaXNlRWRpdG9yLCBiNjREZWNvZGUgfSA9IHdpbmRvdy5fZXhlcmNpc2Vfb2pzX3J1bnRpbWU7XG4gIGNvbnN0IHNjcmlwdENvb
633nRlbnQgPSBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKGBzY3JpcHRbdHlwZT1cXFwid2Vici05LWNvbnRlbnRzXFxcIl1gKS50ZXh0Q29udGVudDtcbiAgY29uc3QgYmxvY2sgPSBKU09OLnBhcnNlKGI2NERlY29kZShzY3JpcHRDb250ZW50KSk7XG5cbiAgY29uc3Qgb3B0aW9ucyA9IE9iamVjdC5hc3NpZ24oeyBpZDogYHdlYnItOS1jb250ZW50c2AgfSwgYmxvY2suYXR0cik7XG4gIGNvbnN0IGVkaXRvciA9IG5ldyBXZWJSRXhlcmNpc2VFZGl0b3Iod2ViUk9qcy53ZWJSUHJvbWlzZSwgYmxvY2suY29kZSwgb3B0aW9ucyk7XG5cbiAgcmV0dXJuIGVkaXRvci5jb250YWluZXI7XG59XG5fd2Vicl92YWx1ZV85ID0gd2ViUk9qcy5wcm9jZXNzKF93ZWJyX2VkaXRvcl85LCB7fSk7XG4ifSx7ImNlbGxOYW1lIjoid2Vici13aWRnZXQtOCIsImlubGluZSI6ZmFsc2UsIm1ldGhvZE5hbWUiOiJpbnRlcnByZXRRdWlldCIsInNvdXJjZSI6IntcbiAgLy8gV2FpdCBmb3Igb3V0cHV0IHRvIGJlIHdyaXR0ZW4gdG8gdGhlIERPTSwgdGhlbiB0cmlnZ2VyIHdpZGdldCByZW5kZXJpbmdcbiAgYXdhaXQgX3dlYnJfdmFsdWVfODtcbiAgaWYgKHdpbmRvdy5IVE1MV2lkZ2V0cykge1xuICAgIHdpbmRvdy5IVE1MV2lkZ2V0cy5zdGF0aWNSZW5kZXIoKTtcbiAgfVxuICBpZiAod2luZG93LlBhZ2VkVGFibGVEb2MpIHtcbiAgICB3aW5kb3cuUGFnZWRUYWJsZURvYy5pbml0QWxsKCk7XG4gIH1cbn1cbiJ9LHsiY2VsbE5hbWUiOiJ3ZWJyLTgiLCJpbmxpbmUiOmZhbHNlLCJtZXRob2ROYW1lIjoiaW50ZXJwcmV0Iiwic291cmNlIjoidmlld29mIF93ZWJyX2VkaXRvcl84ID0ge1xuICBjb25zdCB7IFdlYlJFeGVyY2lzZUVkaXRvciwgYjY0RGVjb2RlIH0gPSB3aW5kb3cuX2V4ZXJjaXNlX29qc19ydW50aW1lO1xuICBjb25zdCBzY3JpcHRDb250ZW50ID0gZG9jdW1lbnQucXVlcnlTZWxlY3Rvcihgc2NyaXB0W3R5cGU9XFxcIndlYnItOC1jb250ZW50c1xcXCJdYCkudGV4dENvbnRlbnQ7XG4gIGNvbnN0IGJsb2NrID0gSlNPTi5wYXJzZShiNjREZWNvZGUoc2NyaXB0Q29udGVudCkpO1xuXG4gIGNvbnN0IG9wdGlvbnMgPSBPYmplY3QuYXNzaWduKHsgaWQ6IGB3ZWJyLTgtY29udGVudHNgIH0sIGJsb2NrLmF0dHIpO1xuICBjb25zdCBlZGl0b3IgPSBuZXcgV2ViUkV4ZXJjaXNlRWRpdG9yKHdlYlJPanMud2ViUlByb21pc2UsIGJsb2NrLmNvZGUsIG9wdGlvbnMpO1xuXG4gIHJldHVybiBlZGl0b3IuY29udGFpbmVyO1xufVxuX3dlYnJfdmFsdWVfOCA9IHdlYlJPanMucHJvY2Vzcyhfd2Vicl9lZGl0b3JfOCwge30pO1xuIn0seyJjZWxsTmFtZSI6IndlYnItd2lkZ2V0LTciLCJpbmxpbmUiOmZhbHNlLCJtZXRob2ROYW1lIjoiaW50ZXJwcmV0UXVpZXQiLCJzb3VyY2UiOiJ7XG4gIC8vIFdhaXQgZm9yIG91dHB1dCB0byBiZSB3cml0dGVuIHRvIHRoZSBET00sIHRoZW4gdHJpZ2dlciB3aWRnZXQgcmVuZGVyaW5nXG4gIGF3YWl0IF93ZWJyX3ZhbHVlXzc7XG4gIGlmICh3aW5kb3cuSFRNTFdpZGdldHMpIHtcbiAgICB3aW5kb3cuSFRNTFdpZGdldHMuc3RhdGljUmVuZGVyKCk7XG4gIH1cbiAgaWYgKHdpbmRvdy5QYWdlZFRhYmxlRG9jKSB7XG4gICAgd2luZG93LlBhZ2VkVGFibGVEb2MuaW5pdEFsbCgpO1xuICB9XG59XG4ifSx7ImNlbGxOYW1lIjoid2Vici03IiwiaW5saW5lIjpmYWxzZSwibWV0aG9kTmFtZSI6ImludGVycHJldCIsInNvdXJjZSI6InZpZXdvZiBfd2Vicl9lZGl0b3JfNyA9IHtcbiAgY29uc3QgeyBXZWJSRXhlcmNpc2VFZGl0b3IsIGI2NERlY29kZSB9ID0gd2luZG93Ll9leGVyY2lzZV9vanNfcnVudGltZTtcbiAgY29uc3Qgc2NyaXB0Q29udGVudCA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoYHNjcmlwdFt0eXBlPVxcXCJ3ZWJyLTctY29udGVudHNcXFwiXWApLnRleHRDb250ZW50O1xuICBjb25zdCBibG9jayA9IEpTT04ucGFyc2UoYjY0RGVjb2RlKHNjcmlwdENvbnRlbnQpKTtcblxuICBjb25zdCBvcHRpb25zID0gT2JqZWN0LmFzc2lnbih7IGlkOiBgd2Vici03LWNvbnRlbnRzYCB9LCBibG9jay5hdHRyKTtcbiAgY29uc3QgZWRpdG9yID0gbmV3IFdlYlJFeGVyY2lzZUVkaXRvcih3ZWJST2pzLndlYlJQcm9taXNlLCBibG9jay5jb2RlLCBvcHRpb25zKTtcblxuICByZXR1cm4gZWRpdG9yLmNvbnRhaW5lcjtcbn1cbl93ZWJyX3ZhbHVlXzcgPSB3ZWJST2pzLnByb2Nlc3MoX3dlYnJfZWRpdG9yXzcsIHt9KTtcbiJ9LHsiY2VsbE5hbWUiOiJ3ZWJyLXdpZGdldC02IiwiaW5saW5lIjpmYWxzZSwibWV0aG9kTmFtZSI6ImludGVycHJldFF1aWV0Iiwic291cmNlIjoie1xuICAvLyBXYWl0IGZvciBvdXRwdXQgdG8gYmUgd3JpdHRlbiB0byB0aGUgRE9NLCB0aGVuIHRyaWdnZXIgd2lkZ2V0IHJlbmRlcmluZ1xuICBhd2FpdCBfd2Vicl92YWx1ZV82O1xuICBpZiAod2luZG93LkhUTUxXaWRnZXRzKSB7XG4gICAgd2luZG93LkhUTUxXaWRnZXRzLnN0YXRpY1JlbmRlcigpO1xuICB9XG4gIGlmICh3aW5kb3cuUGFnZWRUYWJsZURvYykge1xuICAgIHdpbmRvdy5QYWdlZFRhYmxlRG9jLmluaXRBbGwoKTtcbiAgfVxufVxuIn0seyJjZWxsTmFtZSI6IndlYnItNiIsImlubGluZSI6ZmFsc2UsIm1ldGhvZE5hbWUiOiJpbnRlcnByZXQiLCJzb3VyY2UiOiJ2aWV3b2YgX3dlYnJfZWRpdG9yXzYgPSB7XG4gIGNvbnN0IHsgV2ViUkV4ZXJjaXNlRWRpdG9yLCBiNjREZWNvZGUgfSA9IHdpbmRvdy5fZXhlcmNpc2Vfb2pzX3J1bnRpbWU7XG4gIGNvbnN0IHNjcmlwdENvbnRlbnQgPSBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKGBzY3JpcHRbdHlwZT1cXFwid2Vici02LWNvbnRlbnRzXFxcIl1gKS50ZXh0Q29udGVudDtcbiAgY29uc3QgYmxvY2sgPSBKU09OLnBhcnNlKGI2NERlY29kZShzY3JpcHRDb250ZW50KSk7XG5cbiAgY29uc3Qgb3B0aW9ucyA9IE9iamVjdC5hc3NpZ24oeyBpZDogYHdlYnItNi1jb250ZW50c2AgfSwgYmxvY2suYXR0cik7XG4gIGNvbnN0IGVkaXRvciA9IG5ldyBXZWJSRXhlcmNpc2VFZGl0b3Iod2ViUk9qcy53ZWJSUHJvbWlzZSwgYmxvY2suY29kZSwgb3B0aW9ucyk7XG5cbiAgcmV0dXJuIGVkaXRvci5jb250YWluZXI7XG59XG5fd2Vicl92YWx1ZV82ID0gd2ViUk9qcy5wcm9jZXNzKF93ZWJyX2VkaXRvcl82LCB7fSk7XG4ifSx7ImNlbGxOYW1lIjoid2Vici13aWRnZXQtNSIsImlubGluZSI6ZmFsc2UsIm1ldGhvZE5hbWUiOiJpbnRlcnByZXRRdWlldCIsInNvdXJjZSI6IntcbiAgLy8gV2FpdCBmb3Igb3V0cHV0IHRvIGJlIHdyaXR0ZW4gdG8gdGhlIERPTSwgdGhlbiB0cmlnZ2VyIHdpZGdldCByZW5kZXJpbmdcbiAgYXdhaXQgX3dlYnJfdmFsdWVfNTtcbiAgaWYgKHdpbmRvdy5IVE1MV2lkZ2V0cykge1xuICAgIHdpbmRvdy5IVE1MV2lkZ2V0cy5zdGF0aWNSZW5kZXIoKTtcbiAgfVxuICBpZiAod2luZG93LlBhZ2VkVGFibGVEb2MpIHtcbiAgICB3aW5kb3cuUGFnZWRUYWJsZURvYy5pbml0QWxsKCk7XG4gIH1cbn1cbiJ9LHsiY2VsbE5hbWUiOiJ3ZWJyLTUiLCJpbmxpbmUiOmZhbHNlLCJtZXRob2ROYW1lIjoiaW50ZXJwcmV0Iiwic291cmNlIjoidmlld29mIF93ZWJyX2VkaXRvcl81ID0ge1xuICBjb25zdCB7IFdlYlJFeGVyY2lzZUVkaXRvciwgYjY0RGVjb2RlIH0gPSB3aW5kb3cuX2V4ZXJjaXNlX29qc19ydW50aW1lO1xuICBjb25zdCBzY3JpcHRDb250ZW50ID0gZG9jdW1lbnQucXVlcnlTZWxlY3Rvcihgc2NyaXB0W3R5cGU9XFxcIndlYnItNS1jb250ZW50c1xcXCJdYCkudGV4dENvbnRlbnQ7XG4gIGNvbnN0IGJsb2NrID0gSlNPTi5wYXJzZShiNjREZWNvZGUoc2NyaXB0Q29udGVudCkpO1xuXG4gIGNvbnN0IG9wdGlvbnMgPSBPYmplY3QuYXNzaWduKHsgaWQ6IGB3ZWJyLTUtY29udGVudHNgIH0sIGJsb2NrLmF0dHIpO1xuICBjb25zdCBlZGl0b3IgPSBuZXcgV2ViUkV4ZXJjaXNlRWRpdG9yKHdlYlJPanMud2ViUlByb21pc2UsIGJsb2NrLmNvZGUsIG9wdGlvbnMpO1xuXG4gIHJldHVybi
633BlZGl0b3IuY29udGFpbmVyO1xufVxuX3dlYnJfdmFsdWVfNSA9IHdlYlJPanMucHJvY2Vzcyhfd2Vicl9lZGl0b3JfNSwge30pO1xuIn0seyJjZWxsTmFtZSI6IndlYnItd2lkZ2V0LTQiLCJpbmxpbmUiOmZhbHNlLCJtZXRob2ROYW1lIjoiaW50ZXJwcmV0UXVpZXQiLCJzb3VyY2UiOiJ7XG4gIC8vIFdhaXQgZm9yIG91dHB1dCB0byBiZSB3cml0dGVuIHRvIHRoZSBET00sIHRoZW4gdHJpZ2dlciB3aWRnZXQgcmVuZGVyaW5nXG4gIGF3YWl0IF93ZWJyX3ZhbHVlXzQ7XG4gIGlmICh3aW5kb3cuSFRNTFdpZGdldHMpIHtcbiAgICB3aW5kb3cuSFRNTFdpZGdldHMuc3RhdGljUmVuZGVyKCk7XG4gIH1cbiAgaWYgKHdpbmRvdy5QYWdlZFRhYmxlRG9jKSB7XG4gICAgd2luZG93LlBhZ2VkVGFibGVEb2MuaW5pdEFsbCgpO1xuICB9XG59XG4ifSx7ImNlbGxOYW1lIjoid2Vici00IiwiaW5saW5lIjpmYWxzZSwibWV0aG9kTmFtZSI6ImludGVycHJldCIsInNvdXJjZSI6InZpZXdvZiBfd2Vicl9lZGl0b3JfNCA9IHtcbiAgY29uc3QgeyBXZWJSRXhlcmNpc2VFZGl0b3IsIGI2NERlY29kZSB9ID0gd2luZG93Ll9leGVyY2lzZV9vanNfcnVudGltZTtcbiAgY29uc3Qgc2NyaXB0Q29udGVudCA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoYHNjcmlwdFt0eXBlPVxcXCJ3ZWJyLTQtY29udGVudHNcXFwiXWApLnRleHRDb250ZW50O1xuICBjb25zdCBibG9jayA9IEpTT04ucGFyc2UoYjY0RGVjb2RlKHNjcmlwdENvbnRlbnQpKTtcblxuICBjb25zdCBvcHRpb25zID0gT2JqZWN0LmFzc2lnbih7IGlkOiBgd2Vici00LWNvbnRlbnRzYCB9LCBibG9jay5hdHRyKTtcbiAgY29uc3QgZWRpdG9yID0gbmV3IFdlYlJFeGVyY2lzZUVkaXRvcih3ZWJST2pzLndlYlJQcm9taXNlLCBibG9jay5jb2RlLCBvcHRpb25zKTtcblxuICByZXR1cm4gZWRpdG9yLmNvbnRhaW5lcjtcbn1cbl93ZWJyX3ZhbHVlXzQgPSB3ZWJST2pzLnByb2Nlc3MoX3dlYnJfZWRpdG9yXzQsIHt9KTtcbiJ9LHsiY2VsbE5hbWUiOiJ3ZWJyLXdpZGdldC0zIiwiaW5saW5lIjpmYWxzZSwibWV0aG9kTmFtZSI6ImludGVycHJldFF1aWV0Iiwic291cmNlIjoie1xuICAvLyBXYWl0IGZvciBvdXRwdXQgdG8gYmUgd3JpdHRlbiB0byB0aGUgRE9NLCB0aGVuIHRyaWdnZXIgd2lkZ2V0IHJlbmRlcmluZ1xuICBhd2FpdCBfd2Vicl92YWx1ZV8zO1xuICBpZiAod2luZG93LkhUTUxXaWRnZXRzKSB7XG4gICAgd2luZG93LkhUTUxXaWRnZXRzLnN0YXRpY1JlbmRlcigpO1xuICB9XG4gIGlmICh3aW5kb3cuUGFnZWRUYWJsZURvYykge1xuICAgIHdpbmRvdy5QYWdlZFRhYmxlRG9jLmluaXRBbGwoKTtcbiAgfVxufVxuIn0seyJjZWxsTmFtZSI6IndlYnItMyIsImlubGluZSI6ZmFsc2UsIm1ldGhvZE5hbWUiOiJpbnRlcnByZXQiLCJzb3VyY2UiOiJ2aWV3b2YgX3dlYnJfZWRpdG9yXzMgPSB7XG4gIGNvbnN0IHsgV2ViUkV4ZXJjaXNlRWRpdG9yLCBiNjREZWNvZGUgfSA9IHdpbmRvdy5fZXhlcmNpc2Vfb2pzX3J1bnRpbWU7XG4gIGNvbnN0IHNjcmlwdENvbnRlbnQgPSBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKGBzY3JpcHRbdHlwZT1cXFwid2Vici0zLWNvbnRlbnRzXFxcIl1gKS50ZXh0Q29udGVudDtcbiAgY29uc3QgYmxvY2sgPSBKU09OLnBhcnNlKGI2NERlY29kZShzY3JpcHRDb250ZW50KSk7XG5cbiAgY29uc3Qgb3B0aW9ucyA9IE9iamVjdC5hc3NpZ24oeyBpZDogYHdlYnItMy1jb250ZW50c2AgfSwgYmxvY2suYXR0cik7XG4gIGNvbnN0IGVkaXRvciA9IG5ldyBXZWJSRXhlcmNpc2VFZGl0b3Iod2ViUk9qcy53ZWJSUHJvbWlzZSwgYmxvY2suY29kZSwgb3B0aW9ucyk7XG5cbiAgcmV0dXJuIGVkaXRvci5jb250YWluZXI7XG59XG5fd2Vicl92YWx1ZV8zID0gd2ViUk9qcy5wcm9jZXNzKF93ZWJyX2VkaXRvcl8zLCB7fSk7XG4ifSx7ImNlbGxOYW1lIjoid2Vici13aWRnZXQtMiIsImlubGluZSI6ZmFsc2UsIm1ldGhvZE5hbWUiOiJpbnRlcnByZXRRdWlldCIsInNvdXJjZSI6IntcbiAgLy8gV2FpdCBmb3Igb3V0cHV0IHRvIGJlIHdyaXR0ZW4gdG8gdGhlIERPTSwgdGhlbiB0cmlnZ2VyIHdpZGdldCByZW5kZXJpbmdcbiAgYXdhaXQgX3dlYnJfdmFsdWVfMjtcbiAgaWYgKHdpbmRvdy5IVE1MV2lkZ2V0cykge1xuICAgIHdpbmRvdy5IVE1MV2lkZ2V0cy5zdGF0aWNSZW5kZXIoKTtcbiAgfVxuICBpZiAod2luZG93LlBhZ2VkVGFibGVEb2MpIHtcbiAgICB3aW5kb3cuUGFnZWRUYWJsZURvYy5pbml0QWxsKCk7XG4gIH1cbn1cbiJ9LHsiY2VsbE5hbWUiOiJ3ZWJyLTIiLCJpbmxpbmUiOmZhbHNlLCJtZXRob2ROYW1lIjoiaW50ZXJwcmV0Iiwic291cmNlIjoidmlld29mIF93ZWJyX2VkaXRvcl8yID0ge1xuICBjb25zdCB7IFdlYlJFeGVyY2lzZUVkaXRvciwgYjY0RGVjb2RlIH0gPSB3aW5kb3cuX2V4ZXJjaXNlX29qc19ydW50aW1lO1xuICBjb25zdCBzY3JpcHRDb250ZW50ID0gZG9jdW1lbnQucXVlcnlTZWxlY3Rvcihgc2NyaXB0W3R5cGU9XFxcIndlYnItMi1jb250ZW50c1xcXCJdYCkudGV4dENvbnRlbnQ7XG4gIGNvbnN0IGJsb2NrID0gSlNPTi5wYXJzZShiNjREZWNvZGUoc2NyaXB0Q29udGVudCkpO1xuXG4gIGNvbnN0IG9wdGlvbnMgPSBPYmplY3QuYXNzaWduKHsgaWQ6IGB3ZWJyLTItY29udGVudHNgIH0sIGJsb2NrLmF0dHIpO1xuICBjb25zdCBlZGl0b3IgPSBuZXcgV2ViUkV4ZXJjaXNlRWRpdG9yKHdlYlJPanMud2ViUlByb21pc2UsIGJsb2NrLmNvZGUsIG9wdGlvbnMpO1xuXG4gIHJldHVybiBlZGl0b3IuY29udGFpbmVyO1xufVxuX3dlYnJfdmFsdWVfMiA9IHdlYlJPanMucHJvY2Vzcyhfd2Vicl9lZGl0b3JfMiwge30pO1xuIn0seyJjZWxsTmFtZSI6IndlYnItd2lkZ2V0LTEiLCJpbmxpbmUiOmZhbHNlLCJtZXRob2ROYW1lIjoiaW50ZXJwcmV0UXVpZXQiLCJzb3VyY2UiOiJ7XG4gIC8vIFdhaXQgZm9yIG91dHB1dCB0byBiZSB3cml0dGVuIHRvIHRoZSBET00sIHRoZW4gdHJpZ2dlciB3aWRnZXQgcmVuZGVyaW5nXG4gIGF3YWl0IF93ZWJyX3ZhbHVlXzE7XG4gIGlmICh3aW5kb3cuSFRNTFdpZGdldHMpIHtcbiAgICB3aW5kb3cuSFRNTFdpZGdldHMuc3RhdGljUmVuZGVyKCk7XG4gIH1cbiAgaWYgKHdpbmRvdy5QYWdlZFRhYmxlRG9jKSB7XG4gICAgd2luZG93LlBhZ2VkVGFibGVEb2MuaW5pdEFsbCgpO1xuICB9XG59XG4ifSx7ImNlbGxOYW1lIjoid2Vici0xIiwiaW5saW5lIjpmYWxzZSwibWV0aG9kTmFtZSI6ImludGVycHJldCIsInNvdXJjZSI6InZpZXdvZiBfd2Vicl9lZGl0b3JfMSA9IHtcbiAgY29uc3QgeyBXZWJSRXhlcmNpc2VFZGl0b3IsIGI2NERlY29kZSB9ID0gd2luZG93Ll9leGVyY2lzZV9vanNfcnVudGltZTtcbiAgY29uc3Qgc2NyaXB0Q29udGVudCA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoYHNjcmlwdFt0eXBlPVxcXCJ3ZWJyLTEtY29udGVudHNcXFwiXWApLnRleHRDb250ZW50O1xuICBjb25zdCBibG9jayA9IEpTT04ucGFyc2UoYjY0RGVjb2RlKHNjcmlwdENvb
633nRlbnQpKTtcblxuICBjb25zdCBvcHRpb25zID0gT2JqZWN0LmFzc2lnbih7IGlkOiBgd2Vici0xLWNvbnRlbnRzYCB9LCBibG9jay5hdHRyKTtcbiAgY29uc3QgZWRpdG9yID0gbmV3IFdlYlJFeGVyY2lzZUVkaXRvcih3ZWJST2pzLndlYlJQcm9taXNlLCBibG9jay5jb2RlLCBvcHRpb25zKTtcblxuICByZXR1cm4gZWRpdG9yLmNvbnRhaW5lcjtcbn1cbl93ZWJyX3ZhbHVlXzEgPSB3ZWJST2pzLnByb2Nlc3MoX3dlYnJfZWRpdG9yXzEsIHt9KTtcbiJ9LHsiY2VsbE5hbWUiOiJ3ZWJyLXByZWx1ZGUiLCJpbmxpbmUiOmZhbHNlLCJtZXRob2ROYW1lIjoiaW50ZXJwcmV0UXVpZXQiLCJzb3VyY2UiOiJ3ZWJST2pzID0ge1xuICBjb25zdCB7IFdlYlIsIENoYW5uZWxUeXBlIH0gPSB3aW5kb3cuX2V4ZXJjaXNlX29qc19ydW50aW1lLldlYlI7XG4gIGNvbnN0IHtcbiAgICBXZWJSRXZhbHVhdG9yLFxuICAgIFdlYlJFbnZpcm9ubWVudE1hbmFnZXIsXG4gICAgc2V0dXBSLFxuICAgIGI2NERlY29kZSxcbiAgICBjb2xsYXBzZVBhdGhcbiAgfSA9IHdpbmRvdy5fZXhlcmNpc2Vfb2pzX3J1bnRpbWU7XG5cbiAgY29uc3Qgc3RhdHVzQ29udGFpbmVyID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoXCJleGVyY2lzZS1sb2FkaW5nLXN0YXR1c1wiKTtcbiAgY29uc3QgaW5kaWNhdG9yQ29udGFpbmVyID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoXCJleGVyY2lzZS1sb2FkaW5nLWluZGljYXRvclwiKTtcbiAgaW5kaWNhdG9yQ29udGFpbmVyLmNsYXNzTGlzdC5yZW1vdmUoXCJkLW5vbmVcIik7XG5cbiAgbGV0IHN0YXR1c1RleHQgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KFwiZGl2XCIpXG4gIHN0YXR1c1RleHQuY2xhc3NMaXN0ID0gXCJleGVyY2lzZS1sb2FkaW5nLWRldGFpbHNcIjtcbiAgc3RhdHVzVGV4dCA9IHN0YXR1c0NvbnRhaW5lci5hcHBlbmRDaGlsZChzdGF0dXNUZXh0KTtcbiAgc3RhdHVzVGV4dC50ZXh0Q29udGVudCA9IGBJbml0aWFsaXNlYDtcblxuICAvLyBIb2lzdCBpbmRpY2F0b3Igb3V0IGZyb20gZmluYWwgc2xpZGUgd2hlbiBydW5uaW5nIHVuZGVyIHJldmVhbFxuICBjb25zdCByZXZlYWxTdGF0dXMgPSBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKFwiLnJldmVhbCAuZXhlcmNpc2UtbG9hZGluZy1pbmRpY2F0b3JcIik7XG4gIGlmIChyZXZlYWxTdGF0dXMpIHtcbiAgICByZXZlYWxTdGF0dXMucmVtb3ZlKCk7XG4gICAgZG9jdW1lbnQucXVlcnlTZWxlY3RvcihcIi5yZXZlYWwgPiAuc2xpZGVzXCIpLmFwcGVuZENoaWxkKHJldmVhbFN0YXR1cyk7XG4gIH1cblxuICAvLyBNYWtlIGFueSByZXZlYWwgc2xpZGVzIHdpdGggbGl2ZSBjZWxscyBzY3JvbGxhYmxlXG4gIGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3JBbGwoXCIucmV2ZWFsIC5leGVyY2lzZS1jZWxsXCIpLmZvckVhY2goKGVsKSA9PiB7XG4gICAgZWwuY2xvc2VzdCgnc2VjdGlvbi5zbGlkZScpLmNsYXNzTGlzdC5hZGQoXCJzY3JvbGxhYmxlXCIpO1xuICB9KVxuXG4gIC8vIHdlYlIgc3VwcGxlbWVudGFsIGRhdGEgYW5kIG9wdGlvbnNcbiAgY29uc3QgZGF0YUNvbnRlbnQgPSBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKGBzY3JpcHRbdHlwZT1cXFwid2Vici1kYXRhXFxcIl1gKS50ZXh0Q29udGVudDtcbiAgY29uc3QgZGF0YSA9IEpTT04ucGFyc2UoYjY0RGVjb2RlKGRhdGFDb250ZW50KSk7XG5cbiAgLy8gR3JhYiBsaXN0IG9mIHJlc291cmNlcyB0byBiZSBkb3dubG9hZGVkXG4gIGNvbnN0IGZpbGVzQ29udGVudCA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoYHNjcmlwdFt0eXBlPVxcXCJ2ZnMtZmlsZVxcXCJdYCkudGV4dENvbnRlbnQ7XG4gIGNvbnN0IGZpbGVzID0gSlNPTi5wYXJzZShiNjREZWNvZGUoZmlsZXNDb250ZW50KSk7XG5cbiAgLy8gVXNlIFBvc3RNZXNzYWdlIGNoYW5uZWwgZm9yIGFzeW5jIGNvbW11bmljYXRpb25cbiAgLy8gV2UgZG8gbm90IGV4cGVjdCB0byB0YWtlIG5lc3RlZCBwcm9tcHQgaW5wdXQgaW4gUXVhcnRvIExpdmUgY2VsbHNcbiAgZGF0YS5vcHRpb25zLmNoYW5uZWxUeXBlID0gQ2hhbm5lbFR5cGUuUG9zdE1lc3NhZ2U7XG5cbiAgLy8gSW5pdGlhbGlzZSB3ZWJSIGFuZCBzZXR1cCBmb3IgUiBjb2RlIGV2YWx1YXRpb25cbiAgbGV0IHdlYlJQcm9taXNlID0gKGFzeW5jICh3ZWJSKSA9PiB7XG4gICAgc3RhdHVzVGV4dC50ZXh0Q29udGVudCA9IGBEb3dubG9hZGluZyB3ZWJSYDtcbiAgICBhd2FpdCB3ZWJSLmluaXQoKTtcblxuICAgIC8vIEluc3RhbGwgcHJvdmlkZWQgbGlzdCBvZiBwYWNrYWdlc1xuICAgIC8vIEVuc3VyZSB3ZWJSIGRlZmF1bHQgcmVwbyBpcyBpbmNsdWRlZFxuICAgIGRhdGEucGFja2FnZXMucmVwb3MucHVzaChcImh0dHBzOi8vcmVwby5yLXdhc20ub3JnXCIpXG4gICAgYXdhaXQgZGF0YS5wYWNrYWdlcy5wa2dzLm1hcCgocGtnKSA9PiAoKSA9PiB7XG4gICAgICBzdGF0dXNUZXh0LnRleHRDb250ZW50ID0gYERvd25sb2FkaW5nIHBhY2thZ2U6ICR7cGtnfWA7XG4gICAgICByZXR1cm4gd2ViUi5ldmFsUlZvaWQoYFxuICAgICAgICB3ZWJyOjppbnN0YWxsKHBrZywgcmVwb3MgPSByZXBvcylcbiAgICAgICAgbGlicmFyeShwa2csIGNoYXJhY3Rlci5vbmx5ID0gVFJVRSlcbiAgICAgIGAsIHsgZW52OiB7XG4gICAgICAgIHBrZzogcGtnLFxuICAgICAgICByZXBvczogZGF0YS5wYWNrYWdlcy5yZXBvcyxcbiAgICAgIH19KTtcbiAgICB9KS5yZWR1Y2UoKGN1ciwgbmV4dCkgPT4gY3VyLnRoZW4obmV4dCksIFByb21pc2UucmVzb2x2ZSgpKTtcblxuICAgIC8vIERvd25sb2FkIGFuZCBpbnN0YWxsIHJlc291cmNlc1xuICAgIGF3YWl0IGZpbGVzLm1hcCgoZmlsZSkgPT4gYXN5bmMgKCkgPT4ge1xuICAgICAgY29uc3QgbmFtZSA9IGZpbGUuc3Vic3RyaW5nKGZpbGUubGFzdEluZGV4T2YoJy8nKSArIDEpO1xuICAgICAgc3RhdHVzVGV4dC50ZXh0Q29udGVudCA9IGBEb3dubG9hZGluZyByZXNvdXJjZTogJHtuYW1lfWA7XG4gICAgICBjb25zdCByZXNwb25zZSA9IGF3YWl0IGZldGNoKGZpbGUpO1xuICAgICAgaWYgKCFyZXNwb25zZS5vaykge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYENhbid0IGRvd25sb2FkIFxcYCR7ZmlsZX1cXGAuIEVycm9yICR7cmVzcG9uc2Uuc3RhdHVzfTogXCIke3Jlc3BvbnNlLnN0YXR1c1RleHR9XCIuYCk7XG4gICAgICB9XG4gICAgICBjb25zdCBkYXRhID0gYXdhaXQgcmVzcG9uc2UuYXJyYXlCdWZmZXIoKTtcblxuICAgICAgLy8gU3RvcmUgVVJMcyBpbiB0aGUgY3dkIHdpdGhvdXQgYW55IHN1YmRpcmVjdG9yeSBzdHJ1Y3R1cmVcbiAgICAgIGlmIChmaWxlLmluY2x1ZGVzKFwiOi8vXCIpKSB7XG4gICAgICAgIGZpbGUgP
633SBuYW1lO1xuICAgICAgfVxuXG4gICAgICAvLyBDb2xsYXBzZSBoaWdoZXIgZGlyZWN0b3J5IHN0cnVjdHVyZVxuICAgICAgZmlsZSA9IGNvbGxhcHNlUGF0aChmaWxlKTtcblxuICAgICAgLy8gQ3JlYXRlIGRpcmVjdG9yeSB0cmVlLCBpZ25vcmluZyBcImRpcmVjdG9yeSBleGlzdHNcIiBWRlMgZXJyb3JzXG4gICAgICBjb25zdCBwYXJ0cyA9IGZpbGUuc3BsaXQoJy8nKS5zbGljZSgwLCAtMSk7XG4gICAgICBsZXQgcGF0aCA9ICcnO1xuICAgICAgd2hpbGUgKHBhcnRzLmxlbmd0aCA+IDApIHtcbiAgICAgICAgcGF0aCArPSBwYXJ0cy5zaGlmdCgpICsgJy8nO1xuICAgICAgICB0cnkge1xuICAgICAgICAgIGF3YWl0IHdlYlIuRlMubWtkaXIocGF0aCk7XG4gICAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgICBpZiAoIWUubWVzc2FnZS5pbmNsdWRlcyhcIkZTIGVycm9yXCIpKSB7XG4gICAgICAgICAgICB0aHJvdyBlO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICAvLyBXcml0ZSB0aGlzIGZpbGUgdG8gdGhlIFZGU1xuICAgICAgcmV0dXJuIGF3YWl0IHdlYlIuRlMud3JpdGVGaWxlKGZpbGUsIG5ldyBVaW50OEFycmF5KGRhdGEpKTtcbiAgICB9KS5yZWR1Y2UoKGN1ciwgbmV4dCkgPT4gY3VyLnRoZW4obmV4dCksIFByb21pc2UucmVzb2x2ZSgpKTtcblxuICAgIHN0YXR1c1RleHQudGV4dENvbnRlbnQgPSBgSW5zdGFsbGluZyB3ZWJSIHNoaW1zYDtcbiAgICBhd2FpdCB3ZWJSLmV2YWxSVm9pZChgd2Vicjo6c2hpbV9pbnN0YWxsKClgKTtcblxuICAgIHN0YXR1c1RleHQudGV4dENvbnRlbnQgPSBgV2ViUiBlbnZpcm9ubWVudCBzZXR1cGA7XG4gICAgYXdhaXQgc2V0dXBSKHdlYlIsIGRhdGEpO1xuXG4gICAgc3RhdHVzVGV4dC5yZW1vdmUoKTtcbiAgICBpZiAoc3RhdHVzQ29udGFpbmVyLmNoaWxkcmVuLmxlbmd0aCA9PSAwKSB7XG4gICAgICBzdGF0dXNDb250YWluZXIucGFyZW50Tm9kZS5yZW1vdmUoKTtcbiAgICB9XG4gICAgcmV0dXJuIHdlYlI7XG4gIH0pKG5ldyBXZWJSKGRhdGEub3B0aW9ucykpO1xuXG4gIC8vIEtlZXAgdHJhY2sgb2YgaW5pdGlhbCBPSlMgYmxvY2sgcmVuZGVyXG4gIGNvbnN0IHJlbmRlcmVkT2pzID0ge307XG5cbiAgY29uc3QgcHJvY2VzcyA9IGFzeW5jIChjb250ZXh0LCBpbnB1dHMpID0+IHtcbiAgICBjb25zdCB3ZWJSID0gYXdhaXQgd2ViUlByb21pc2U7XG4gICAgY29uc3QgZXZhbHVhdG9yID0gbmV3IFdlYlJFdmFsdWF0b3Iod2ViUiwgY29udGV4dClcbiAgICBhd2FpdCBldmFsdWF0b3IucHJvY2VzcyhpbnB1dHMpO1xuICAgIHJldHVybiBldmFsdWF0b3IuY29udGFpbmVyO1xuICB9XG5cbiAgcmV0dXJuIHtcbiAgICBwcm9jZXNzLFxuICAgIHdlYlJQcm9taXNlLFxuICAgIHJlbmRlcmVkT2pzLFxuICB9O1xufVxuIn1dfQ==
634</script>
634
635<div id="exercise-loading-indicator" class="exercise-loading-indicator d-none d-flex align-items-center gap-2">
636<div id="exercise-loading-status" class="d-flex gap-2">
637
638</div>
639<div class="spinner-grow spinner-grow-sm">
640
641</div>
642</div>
643<script type="vfs-file">
644W10=
645</script>
645
646</section>
647</section>
648
649</main> <!-- /main -->
650<script type="ojs-module-contents">
651eyJjb250ZW50cyI6W119
652</script>
vendor: 1 bytes, line 652
652
653<script type="module">
654if (window.location.protocol === "file:") { alert("The OJS runtime does not work with file:// URLs. Please use a web server to view this document."); }
655window._ojs.paths.runtimeToDoc = "../..";
656window._ojs.paths.runtimeToRoot = "../..";
657window._ojs.paths.docToRoot = "";
658window._ojs.selfContained = false;
659window._ojs.runtime.interpretFromScriptTags();
660</script>
vendor: 1 bytes, line 660
660
661<script id="quarto-html-after-body" type="application/javascript">
662window.document.addEventListener("DOMContentLoaded", function (event) {
663  const toggleBodyColorMode = (bsSheetEl) => {
664    const mode = bsSheetEl.getAttribute("data-mode");
665    const bodyEl = window.document.querySelector("body");
666    if (mode === "dark") {
667      bodyEl.classList.add("quarto-dark");
668      bodyEl.classList.remove("quarto-light");
669    } else {
670      bodyEl.classList.add("quarto-light");
671      bodyEl.classList.remove("quarto-dark");
672    }
673  }
674  const toggleBodyColorPrimary = () => {
675    const bsSheetEl = window.document.querySelector("link#quarto-bootstrap");
676    if (bsSheetEl) {
677      toggleBodyColorMode(bsSheetEl);
678    }
679  }
680  toggleBodyColorPrimary();  
681  const icon = "";
682  const anchorJS = new window.AnchorJS();
683  anchorJS.options = {
684    placement: 'right',
685    icon: icon
686  };
687  anchorJS.add('.anchored');
688  const isCodeAnnotation = (el) => {
689    for (const clz of el.classList) {
690      if (clz.startsWith('code-annotation-')) {                     
691        return true;
692      }
693    }
694    return false;
695  }
696  const onCopySuccess = function(e) {
697    // button target
698    const button = e.trigger;
699    // don't keep focus
700    button.blur();
701    // flash "checked"
702    button.classList.add('code-copy-button-checked');
703    var currentTitle = button.getAttribute("title");
704    button.setAttribute("title", "Copied!");
705    let tooltip;
706    if (window.bootstrap) {
707      button.setAttribute("data-bs-toggle", "tooltip");
708      button.setAttribute("data-bs-placement", "left");
709      button.setAttribute("data-bs-title", "Copied!");
710      tooltip = new bootstrap.Tooltip(button, 
711        { trigger: "manual", 
712          customClass: "code-copy-button-tooltip",
713          offset: [0, -8]});
714      tooltip.show();    
715    }
716    setTimeout(function() {
717      if (tooltip) {
718        tooltip.hide();
719        button.removeAttribute("data-bs-title");
720        button.removeAttribute("data-bs-toggle");
721        button.removeAttribute("data-bs-placement");
722      }
723      button.setAttribute("title", currentTitle);
724      button.classList.remove('code-copy-button-checked');
725    }, 1000);
726    // clear code selection
727    e.clearSelection();
728  }
729  const getTextToCopy = function(trigger) {
730      const codeEl = trigger.previousElementSibling.cloneNode(true);
731      for (const childEl of codeEl.children) {
732        if (isCodeAnnotation(childEl)) {
733          childEl.remove();
734        }
735      }
736      return codeEl.innerText;
737  }
738  const clipboard = new window.ClipboardJS('.code-copy-button:not([data-in-quarto-modal])', {
739    text: getTextToCopy
740  });
741  clipboard.on('success', onCopySuccess);
742  if (window.document.getElementById('quarto-embedded-source-code-modal')) {
743    const clipboardModal = new window.ClipboardJS('.code-copy-button[data-in-quarto-modal]', {
744      text: getTextToCopy,
745      container: window.document.getElementById('quarto-embedded-source-code-modal')
746    });
747    clipboardModal.on('success', onCopySuccess);
748  }
749    var localhostRegex = new RegExp(/^(?:http|https):\/\/localhost\:?[0-9]*\//);
750    var mailtoRegex = new RegExp(/^mailto:/);
751      var filterRegex = new RegExp("https:\/\/drb-workshops-portfolio\.netlify\.app");
752    var isInternal = (href) => {
753        return filterRegex.test(href) || localhostRegex.test(href) || mailtoRegex.test(href);
754    }
755    // Inspect non-navigation links and adorn them if external
756 	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)');
757    for (var i=0; i<links.length; i++) {
758      const link = links[i];
759      if (!isInternal(link.href)) {
760        // undo the damage that might have been done by quarto-nav.js in the case of
761        // links that we want to consider external
762        if (link.dataset.originalHref !== undefined) {
763          link.href = link.dataset.originalHref;
764        }
765      }
766    }
767  function tippyHover(el, contentFn, onTriggerFn, onUntriggerFn) {
768    const config = {
769      allowHTML: true,
770      maxWidth: 500,
771      delay: 100,
772      arrow: false,
773      appendTo: function(el) {
774          return el.parentElement;
775      },
776      interactive: true,
777      interactiveBorder: 10,
778      theme: 'quarto',
779      placement: 'bottom-start',
780    };
781    if (contentFn) {
782      config.content = contentFn;
783    }
784    if (onTriggerFn) {
785      config.onTrigger = onTriggerFn;
786    }
787    if (onUntriggerFn) {
788      config.onUntrigger = onUntriggerFn;
789    }
790    window.tippy(el, config); 
791  }
792  const noterefs = window.document.querySelectorAll('a[role="doc-noteref"]');
793  for (var i=0; i<noterefs.length; i++) {
794    const ref = noterefs[i];
795    tippyHover(ref, function() {
796      // use id or data attribute instead here
797      let href = ref.getAttribute('data-footnote-href') || ref.getAttribute('href');
798      try { href = new URL(href).hash; } catch {}
799      const id = href.replace(/^#\/?/, "");
800      const note = window.document.getElementById(id);
801      if (note) {
802        return note.innerHTML;
803      } else {
804        return "";
805      }
806    });
807  }
808  const xrefs = window.document.querySelectorAll('a.quarto-xref');
809  const processXRef = (id, note) => {
810    // Strip column container classes
811    const stripColumnClz = (el) => {
812      el.classList.remove("page-full", "page-columns");
813      if (el.children) {
814        for (const child of el.children) {
815          stripColumnClz(child);
816        }
817      }
818    }
819    stripColumnClz(note)
820    if (id === null || id.startsWith('sec-')) {
821      // Special case sections, only their first couple elements
822      const container = document.createElement("div");
823      if (note.children && note.children.length > 2) {
824        container.appendChild(note.children[0].cloneNode(true));
825        for (let i = 1; i < note.children.length; i++) {
826          const child = note.children[i];
827          if (child.tagName === "P" && child.innerText === "") {
828            continue;
829          } else {
830            container.appendChild(child.cloneNode(true));
831            break;
832          }
833        }
834        if (window.Quarto?.typesetMath) {
835          window.Quarto.typesetMath(container);
836        }
837        return container.innerHTML
838      } else {
839        if (window.Quarto?.typesetMath) {
840          window.Quarto.typesetMath(note);
841        }
842        return note.innerHTML;
843      }
844    } else {
845      // Remove any anchor links if they are present
846      const anchorLink = note.querySelector('a.anchorjs-link');
847      if (anchorLink) {
848        anchorLink.remove();
849      }
850      if (window.Quarto?.typesetMath) {
851        window.Quarto.typesetMath(note);
852      }
853      if (note.classList.contains("callout")) {
854        return note.outerHTML;
855      } else {
856        return note.innerHTML;
857      }
858    }
859  }
860  for (var i=0; i<xrefs.length; i++) {
861    const xref = xrefs[i];
862    tippyHover(xref, undefined, function(instance) {
863      instance.disable();
864      let url = xref.getAttribute('href');
865      let hash = undefined; 
866      if (url.startsWith('#')) {
867        hash = url;
868      } else {
869        try { hash = new URL(url).hash; } catch {}
870      }
871      if (hash) {
872        const id = hash.replace(/^#\/?/, "");
873        const note = window.document.getElementById(id);
874        if (note !== null) {
875          try {
876            const html = processXRef(id, note.cloneNode(true));
877            instance.setContent(html);
878          } finally {
879            instance.enable();
880            instance.show();
881          }
882        } else {
883          // See if we can fetch this
884          fetch(url.split('#')[0])
885          .then(res => res.text())
886          .then(html => {
887            const parser = new DOMParser();
888            const htmlDoc = parser.parseFromString(html, "text/html");
889            const note = htmlDoc.getElementById(id);
890            if (note !== null) {
891              const html = processXRef(id, note);
892              instance.setContent(html);
893            } 
894          }).finally(() => {
895            instance.enable();
896            instance.show();
897          });
898        }
899      } else {
900        // See if we can fetch a full url (with no hash to target)
901        // This is a special case and we should probably do some content thinning / targeting
902        fetch(url)
903        .then(res => res.text())
904        .then(html => {
905          const parser = new DOMParser();
906          const htmlDoc = parser.parseFromString(html, "text/html");
907          const note = htmlDoc.querySelector('main.content');
908          if (note !== null) {
909            // This should only happen for chapter cross references
910            // (since there is no id in the URL)
911            // remove the first header
912            if (note.children.length > 0 && note.children[0].tagName === "HEADER") {
913              note.children[0].remove();
914            }
915            const html = processXRef(null, note);
916            instance.setContent(html);
917          } 
918        }).finally(() => {
919          instance.enable();
920          instance.show();
921        });
922      }
923    }, function(instance) {
924    });
925  }
926      let selectedAnnoteEl;
927      const selectorForAnnotation = ( cell, annotation) => {
928        let cellAttr = 'data-code-cell="' + cell + '"';
929        let lineAttr = 'data-code-annotation="' +  annotation + '"';
930        const selector = 'span[' + cellAttr + '][' + lineAttr + ']';
931        return selector;
932      }
933      const selectCodeLines = (annoteEl) => {
934        const doc = window.document;
935        const targetCell = annoteEl.getAttribute("data-target-cell");
936        const targetAnnotation = annoteEl.getAttribute("data-target-annotation");
937        const annoteSpan = window.document.querySelector(selectorForAnnotation(targetCell, targetAnnotation));
938        const lines = annoteSpan.getAttribute("data-code-lines").split(",");
939        const lineIds = lines.map((line) => {
940          return targetCell + "-" + line;
941        })
942        let top = null;
943        let height = null;
944        let parent = null;
945        if (lineIds.length > 0) {
946            //compute the position of the single el (top and bottom and make a div)
947            const el = window.document.getElementById(lineIds[0]);
948            top = el.offsetTop;
949            height = el.offsetHeight;
950            parent = el.parentElement.parentElement;
951          if (lineIds.length > 1) {
952            const lastEl = window.document.getElementById(lineIds[lineIds.length - 1]);
953            const bottom = lastEl.offsetTop + lastEl.offsetHeight;
954            height = bottom - top;
955          }
956          if (top !== null && height !== null && parent !== null) {
957            // cook up a div (if necessary) and position it 
958            let div = window.document.getElementById("code-annotation-line-highlight");
959            if (div === null) {
960              div = window.document.createElement("div");
961              div.setAttribute("id", "code-annotation-line-highlight");
962              div.style.position = 'absolute';
963              parent.appendChild(div);
964            }
965            div.style.top = top - 2 + "px";
966            div.style.height = height + 4 + "px";
967            div.style.left = 0;
968            let gutterDiv = window.document.getElementById("code-annotation-line-highlight-gutter");
969            if (gutterDiv === null) {
970              gutterDiv = window.document.createElement("div");
971              gutterDiv.setAttribute("id", "code-annotation-line-highlight-gutter");
972              gutterDiv.style.position = 'absolute';
973              const codeCell = window.document.getElementById(targetCell);
974              const gutter = codeCell.querySelector('.code-annotation-gutter');
975              gutter.appendChild(gutterDiv);
976            }
977            gutterDiv.style.top = top - 2 + "px";
978            gutterDiv.style.height = height + 4 + "px";
979          }
980          selectedAnnoteEl = annoteEl;
981        }
982      };
983      const unselectCodeLines = () => {
984        const elementsIds = ["code-annotation-line-highlight", "code-annotation-line-highlight-gutter"];
985        elementsIds.forEach((elId) => {
986          const div = window.document.getElementById(elId);
987          if (div) {
988            div.remove();
989          }
990        });
991        selectedAnnoteEl = undefined;
992      };
993        // Handle positioning of the toggle
994    window.addEventListener(
995      "resize",
996      throttle(() => {
997        elRect = undefined;
998        if (selectedAnnoteEl) {
999          selectCodeLines(selectedAnnoteEl);
1000        }
1001      }, 10)
1002    );
1003    function throttle(fn, ms) {
1004    let throttle = false;
1005    let timer;
1006      return (...args) => {
1007        if(!throttle) { // first call gets through
1008            fn.apply(this, args);
1009            throttle = true;
1010        } else { // all the others get throttled
1011            if(timer) clearTimeout(timer); // cancel #2
1012            timer = setTimeout(() => {
1013              fn.apply(this, args);
1014              timer = throttle = false;
1015            }, ms);
1016        }
1017      };
1018    }
1019      // Attach click handler to the DT
1020      const annoteDls = window.document.querySelectorAll('dt[data-target-cell]');
1021      for (const annoteDlNode of annoteDls) {
1022        annoteDlNode.addEventListener('click', (event) => {
1023          const clickedEl = event.target;
1024          if (clickedEl !== selectedAnnoteEl) {
1025            unselectCodeLines();
1026            const activeEl = window.document.querySelector('dt[data-target-cell].code-annotation-active');
1027            if (activeEl) {
1028              activeEl.classList.remove('code-annotation-active');
1029            }
1030            selectCodeLines(clickedEl);
1031            clickedEl.classList.add('code-annotation-active');
1032          } else {
1033            // Unselect the line
1034            unselectCodeLines();
1035            clickedEl.classList.remove('code-annotation-active');
1036          }
1037        });
1038      }
1039  const findCites = (el) => {
1040    const parentEl = el.parentElement;
1041    if (parentEl) {
1042      const cites = parentEl.dataset.cites;
1043      if (cites) {
1044        return {
1045          el,
1046          cites: cites.split(' ')
1047        };
1048      } else {
1049        return findCites(el.parentElement)
1050      }
1051    } else {
1052      return undefined;
1053    }
1054  };
1055  var bibliorefs = window.document.querySelectorAll('a[role="doc-biblioref"]');
1056  for (var i=0; i<bibliorefs.length; i++) {
1057    const ref = bibliorefs[i];
1058    const citeInfo = findCites(ref);
1059    if (citeInfo) {
1060      tippyHover(citeInfo.el, function() {
1061        var popup = window.document.createElement('div');
1062        citeInfo.cites.forEach(function(cite) {
1063          var citeDiv = window.document.createElement('div');
1064          citeDiv.classList.add('hanging-indent');
1065          citeDiv.classList.add('csl-entry');
1066          var biblioDiv = window.document.getElementById('ref-' + cite);
1067          if (biblioDiv) {
1068            citeDiv.innerHTML = biblioDiv.innerHTML;
1069          }
1070          popup.appendChild(citeDiv);
1071        });
1072        return popup.innerHTML;
1073      });
1074    }
1075  }
1076});
1077</script>
1077
1078</div> <!-- /content -->
1079
1080
1081
1082
1083</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.