PageSourceSearch

https://xpsong.com/courses.html

html xpsong.com collected 2026-10-09 22:09:16 UTC 60,881 bytes, 1,560 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.7.27">
6
7<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
8
9
10<title>Courses – XP Song</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/quarto-nav/headroom.min.js"></script>
vendor: 1 bytes, line 27
27
28<script src="site_libs/clipboard/clipboard.min.js"></script>
vendor: 1 bytes, line 28
28
29<script src="site_libs/quarto-search/autocomplete.umd.js"></script>
vendor: 1 bytes, line 29
29
30<script src="site_libs/quarto-search/fuse.min.js"></script>
vendor: 1 bytes, line 30
30
31<script src="site_libs/quarto-search/quarto-search.js"></script>
31
32<meta name="quarto:offset" content="./">
33<link href="./images/icon.png" rel="icon" type="image/png">
34<script src="site_libs/quarto-html/quarto.js" type="module"></script>
vendor: 1 bytes, line 34
34
35<script src="site_libs/quarto-html/tabsets/tabsets.js" type="module"></script>
vendor: 1 bytes, line 35
35
36<script src="site_libs/quarto-html/popper.min.js"></script>
vendor: 1 bytes, line 36
36
37<script src="site_libs/quarto-html/tippy.umd.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-985aa47af68dae11cd4d235c71fb941e.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-352d2168f5014ef2ecf06eb4ef66f56e.min.css" rel="stylesheet" append-hash="true" id="quarto-bootstrap" data-mode="light">
43<script src="site_libs/quarto-contrib/iconify-1.0.7/iconify-icon.min.js"></script>
43
44<link href="site_libs/quarto-contrib/fontawesome6-0.1.0/all.css" rel="stylesheet">
45<link href="site_libs/quarto-contrib/fontawesome6-0.1.0/latex-fontsize.css" rel="stylesheet">
46<link href="site_libs/quarto-contrib/academicons-1.9.2/all.css" rel="stylesheet">
47<link href="site_libs/quarto-contrib/academicons-1.9.2/size.css" rel="stylesheet">
48<script id="quarto-search-options" type="application/json">{
49  "location": "navbar",
50  "copy-button": false,
51  "collapse-after": 3,
52  "panel-placement": "end",
53  "type": "overlay",
54  "limit": 50,
55  "keyboard-shortcut": [
56    "f",
57    "/",
58    "s"
59  ],
60  "language": {
61    "search-no-results-text": "No results",
62    "search-matching-documents-text": "matching documents",
63    "search-copy-link-title": "Copy link to search",
64    "search-hide-matches-text": "Hide additional matches",
65    "search-more-match-text": "more match in this document",
66    "search-more-matches-text": "more matches in this document",
67    "search-clear-button-title": "Clear",
68    "search-text-placeholder": "",
69    "search-detached-cancel-button-title": "Cancel",
70    "search-submit-button-title": "Submit",
71    "search-label": "Search"
72  }
73}</script>
vendor: 67 bytes, lines 73-74
73
74<script async="" src="https://www.googletagmanager.com/gtag/js?id=
74G-WS5CZJ06W0
vendor: 13 bytes, lines 74-75
74"></script>
75
76<script type="text/javascript">
77
vendor: 127 bytes, lines 78-81
78window.dataLayer = window.dataLayer || [];
79function gtag(){dataLayer.push(arguments);}
80gtag('js', new Date());
81gtag('config', '
81G-WS5CZJ06W0
vendor: 29 bytes, line 81
81', { 'anonymize_ip': true});
82</script>
82
83
84
85<meta property="og:title" content="Courses">
86<meta property="og:site_name" content="XP's Website">
87<meta property="og:image:width" content="168">
88<meta name="twitter:title" content="Courses">
89<meta name="twitter:creator" content="@dr_watchnlearn">
90<meta name="twitter:card" content="summary">
91</head>
92
93<body class="nav-fixed fullcontent quarto-light">
94
95<div id="quarto-search-results"></div>
96  <header id="quarto-header" class="headroom fixed-top">
97    <nav class="navbar navbar-expand-lg " data-bs-theme="dark">
98      <div class="navbar-container container-fluid">
99      <div class="navbar-brand-container mx-auto">
100    <a href="./index.html" class="navbar-brand navbar-brand-logo">
101    <img src="./images/icon.png" alt="XP's Website" class="navbar-logo">
102    </a>
103  </div>
104            <div id="quarto-search" class="" title="Search"></div>
105          <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(); }">
106  <span class="navbar-toggler-icon"></span>
107</button>
108          <div class="collapse navbar-collapse" id="navbarCollapse">
109            <ul class="navbar-nav navbar-nav-scroll ms-auto">
110  <li class="nav-item">
111    <a class="nav-link active" href="./courses.html" aria-current="page"> 
112<span class="menu-text">Courses</span></a>
113  </li>  
114  <li class="nav-item">
115    <a class="nav-link" href="./blog.html"> 
116<span class="menu-text">Blog</span></a>
117  </li>  
118  <li class="nav-item">
119    <a class="nav-link" href="./academia.html"> 
120<span class="menu-text">Academia</span></a>
121  </li>  
122  <li class="nav-item">
123    <a class="nav-link" href="./music.html"> 
124<span class="menu-text">Music</span></a>
125  </li>  
126</ul>
127          </div> <!-- /navcollapse -->
128            <div class="quarto-navbar-tools">
129</div>
130      </div> <!-- /container-fluid -->
131    </nav>
132</header>
133<!-- content -->
134<div id="quarto-content" class="quarto-container page-layout-custom page-navbar">
135<!-- sidebar -->
136<!-- margin-sidebar -->
137<!-- main -->
138
139
140<header id="title-block-header" class="quarto-title-block default">
141<div class="quarto-title">
142<h1 class="title">Courses</h1>
143</div>
144
145
146
147<div class="quarto-title-meta">
148
149    
150  
151    
152  </div>
153  
154
155
156</header>
157
158
159
160<style>
161
162h1.title {
163  font-size: 0rem;
164}
165
166#quarto-content {
167 background-color: white; 
168 color: #000000;
169 margin-bottom: -20px;
170}
171
172.nav-footer {
173 background-color: #ffffff; 
174 color: #000000;
175}
176.nav-footer a{
177 color: #000000;
178}
179
180h1 {
181  font-family: "Raleway", sans-serif;
182  font-size: 30px;
183  font-weight: 900;
184  color: #000000;
185}
186
187h2 {
188  font-family: "Raleway", sans-serif;
189  font-size: 24px;
190  font-weight: 800;
191  color: #000000;
192  border-bottom: 0px;
193}
194
195.fa-brands {
196  color: black;
197}
198
199.ai {
200  color: black;
201}
202
203.img-roundcrop {
204  border-radius: 50%;
205  height: 180px;
206  width: 180px;
207}
208
209.icon-center{
210  margin: 0!important;
211  height: 55px;
212  vertical-align: center;
213}
214
215</style>
216<center>
217<div class="grid">
218<div class="g-col-2">
219
220</div>
221<div class="g-col-8">
222<p><br></p>
223<p><img src="images/profile.jpg" class="img-roundcrop"></p>
224<section id="dr.-xiao-ping-xp-song" class="level1">
225<h1>Dr.&nbsp;Xiao Ping (XP) Song</h1>
226<p>I teach university and online courses about topics related to geospatial data science, statistical programming and environmental planning.</p>
227<p><strong>Let’s connect!</strong></p>
228<p><a href="https://bit.ly/geospatial-datascience-r_udemy"><iconify-icon inline="" icon="logos:udemy" style="font-size: 1.25em;"></iconify-icon></a> &nbsp; &nbsp; <a href="https://www.linkedin.com/in/xpsong"><i class="fa-brands fa-linkedin fa-xl" aria-label="linkedin"></i></a> &nbsp; &nbsp; <a href="https://www.youtube.com/@dr.watchnlearn"><i class="fa-brands fa-youtube fa-xl" aria-label="youtube"></i></a> &nbsp; &nbsp; <a href="https://twitter.com/dr_watchnlearn"><i class="fa-brands fa-twitter fa-xl" aria-label="twitter"></i></a> &nbsp; &nbsp; <a href="https://scholar.google.com.sg/citations?user=_ZlnqLoAAAAJ"><i class="ai  ai-google-scholar ai-xl"></i></a> &nbsp; &nbsp; <a href="resources/resume_xpsong.pdf"><i class="ai  ai-cv ai-xl"></i></a> &nbsp;</p>
229<p><br><br></p>
230<p><intro video=""></intro></p>
231<p><br><br></p>
232<section id="online-courses" class="level2">
233<h2 data-anchor-id="online-courses">Online courses</h2>
234<p><br><strong>Geospatial Data Science with R</strong> ➡ <a href="https://bit.ly/geospatial-datascience-r_udemy">Go to course</a></p>
235<div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;">
236<iframe src="https://www.youtube.com/embed/playlist?list=PLn_S1vjm5cr29NH4BwcgG-K31_VG6dgtm" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" allowfullscreen="" title="Geospatial Data Science with R">
237</iframe>
238</div>
239<p><br><br><br></p>
240<hr>
241<style type="text/css">@import url("https://assets.mlcdn.com/fonts.css?version=1690874");</style>
242    <style type="text/css">
243    /* LOADER */
244    .ml-form-embedSubmitLoad {
245      display: inline-block;
246      width: 20px;
247      height: 20px;
248    }
249
250    .g-recaptcha {
251    transform: scale(1);
252    -webkit-transform: scale(1);
253    transform-origin: 0 0;
254    -webkit-transform-origin: 0 0;
255    height: ;
256    }
257
258    .sr-only {
259      position: absolute;
260      width: 1px;
261      height: 1px;
262      padding: 0;
263      margin: -1px;
264      overflow: hidden;
265      clip: rect(0,0,0,0);
266      border: 0;
267    }
268
269    .ml-form-embedSubmitLoad:after {
270      content: " ";
271      display: block;
272      width: 11px;
273      height: 11px;
274      margin: 1px;
275      border-radius: 50%;
276      border: 4px solid #fff;
277    border-color: #ffffff #ffffff #ffffff transparent;
278    animation: ml-form-embedSubmitLoad 1.2s linear infinite;
279    }
280    @keyframes ml-form-embedSubmitLoad {
281      0% {
282      transform: rotate(0deg);
283      }
284      100% {
285      transform: rotate(360deg);
286      }
287    }
288      #mlb2-6731696.ml-form-embedContainer {
289        box-sizing: border-box;
290        display: table;
291        margin: 0 auto;
292        position: static;
293        width: 100% !important;
294      }
295      #mlb2-6731696.ml-form-embedContainer h4,
296      #mlb2-6731696.ml-form-embedContainer p,
297      #mlb2-6731696.ml-form-embedContainer span,
298      #mlb2-6731696.ml-form-embedContainer button {
299        text-transform: none !important;
300        letter-spacing: normal !important;
301      }
302      #mlb2-6731696.ml-form-embedContainer .ml-form-embedWrapper {
303        background-color: #ffffff;
304        
305        border-width: 0px;
306        border-color: transparent;
307        border-radius: 4px;
308        border-style: solid;
309        box-sizing: border-box;
310        display: inline-block !important;
311        margin: 0;
312        padding: 0;
313        position: relative;
314              }
315      #mlb2-6731696.ml-form-embedContainer .ml-form-embedWrapper.embedPopup,
316      #mlb2-6731696.ml-form-embedContainer .ml-form-embedWrapper.embedDefault { width: 410px; }
317      #mlb2-6731696.ml-form-embedContainer .ml-form-embedWrapper.embedForm { max-width: 410px; width: 100%; }
318      #mlb2-6731696.ml-form-embedContainer .ml-form-align-left { text-align: left; }
319      #mlb2-6731696.ml-form-embedContainer .ml-form-align-center { text-align: center; }
320      #mlb2-6731696.ml-form-embedContainer .ml-form-align-default { display: table-cell !important; vertical-align: middle !important; text-align: center !important; }
321      #mlb2-6731696.ml-form-embedContainer .ml-form-align-right { text-align: right; }
322      #mlb2-6731696.ml-form-embedContainer .ml-form-embedWrapper .ml-form-embedHeader img {
323        border-top-left-radius: 4px;
324        border-top-right-radius: 4px;
325        height: auto;
326        margin: 0 auto !important;
327        max-width: 100%;
328        width: undefinedpx;
329      }
330      #mlb2-6731696.ml-form-embedContainer .ml-form-embedWrapper .ml-form-embedBody,
331      #mlb2-6731696.ml-form-embedContainer .ml-form-embedWrapper .ml-form-successBody {
332        padding: 20px 20px 0 20px;
333      }
334      #mlb2-6731696.ml-form-embedContainer .ml-form-embedWrapper .ml-form-embedBody.ml-form-embedBodyHorizontal {
335        padding-bottom: 0;
336      }
337      #mlb2-6731696.ml-form-embedContainer .ml-form-embedWrapper .ml-form-embedBody .ml-form-embedContent,
338      #mlb2-6731696.ml-form-embedContainer .ml-form-embedWrapper .ml-form-successBody .ml-form-successContent {
339        text-align: left;
340        margin: 0 0 20px 0;
341      }
342      #mlb2-6731696.ml-form-embedContainer .ml-form-embedWrapper .ml-form-embedBody .ml-form-embedContent h4,
343      #mlb2-6731696.ml-form-embedContainer .ml-form-embedWrapper .ml-form-successBody .ml-form-successContent h4 {
344        color: #1a1a1a;
345        font-family: 'Raleway', sans-serif;
346        font-size: 20px;
347        font-weight: 700;
348        margin: 0 0 10px 0;
349        text-align: center;
350        word-break: break-word;
351      }
352      #mlb2-6731696.ml-form-embedContainer .ml-form-embedWrapper .ml-form-embedBody .ml-form-embedContent p,
353      #mlb2-6731696.ml-form-embedContainer .ml-form-embedWrapper .ml-form-successBody .ml-form-successContent p {
354        color: #343a40;
355        font-family: 'Raleway', sans-serif;
356        font-size: 14px;
357        font-weight: 400;
358        line-height: 20px;
359        margin: 0 0 10px 0;
360        text-align: center;
361      }
362      #mlb2-6731696.ml-form-embedContainer .ml-form-embedWrapper .ml-form-embedBody .ml-form-embedContent ul,
363      #mlb2-6731696.ml-form-embedContainer .ml-form-embedWrapper .ml-form-embedBody .ml-form-embedContent ol,
364      #mlb2-6731696.ml-form-embedContainer .ml-form-embedWrapper .ml-form-successBody .ml-form-successContent ul,
365      #mlb2-6731696.ml-form-embedContainer .ml-form-embedWrapper .ml-form-successBody .ml-form-successContent ol {
366        color: #343a40;
367        font-family: 'Raleway', sans-serif;
368        font-size: 14px;
369      }
370      #mlb2-6731696.ml-form-embedContainer .ml-form-embedWrapper .ml-form-embedBody .ml-form-embedContent ol ol,
371      #mlb2-6731696.ml-form-embedContainer .ml-form-embedWrapper .ml-form-successBody .ml-form-successContent ol ol {
372        list-style-type: lower-alpha;
373      }
374      #mlb2-6731696.ml-form-embedContainer .ml-form-embedWrapper .ml-form-embedBody .ml-form-embedContent ol ol ol,
375      #mlb2-6731696.ml-form-embedContainer .ml-form-embedWrapper .ml-form-successBody .ml-form-successContent ol ol ol {
376        list-style-type: lower-roman;
377      }
378      #mlb2-6731696.ml-form-embedContainer .ml-form-embedWrapper .ml-form-embedBody .ml-form-embedContent p a,
379      #mlb2-6731696.ml-form-embedContainer .ml-form-embedWrapper .ml-form-successBody .ml-form-successContent p a {
380        color: #343a40;
381        text-decoration: underline;
382      }
383
384      #mlb2-6731696.ml-form-embedContainer .ml-form-embedWrapper .ml-block-form .ml-field-group {
385        text-align: left!important;
386      }
387
388      #mlb2-6731696.ml-form-embedContainer .ml-form-embedWrapper .ml-block-form .ml-field-group label {
389        margin-bottom: 5px;
390        color: #333333;
391        font-size: 14px;
392        font-family: 'Open Sans', Arial, Helvetica, sans-serif;
393        font-weight: bold; font-style: normal; text-decoration: none;;
394        display: inline-block;
395        line-height: 20px;
396      }
397      #mlb2-6731696.ml-form-embedContainer .ml-form-embedWrapper .ml-form-embedBody .ml-form-embedContent p:last-child,
398      #mlb2-6731696.ml-form-embedContainer .ml-form-embedWrapper .ml-form-successBody .ml-form-successContent p:last-child {
399        margin: 0;
400      }
401      #mlb2-6731696.ml-form-embedContainer .ml-form-embedWrapper .ml-form-embedBody form {
402        margin: 0;
403        width: 100%;
404      }
405      #mlb2-6731696.ml-form-embedContainer .ml-form-embedWrapper .ml-form-embedBody .ml-form-formContent,
406      #mlb2-6731696.ml-form-embedContainer .ml-form-embedWrapper .ml-form-embedBody .ml-form-checkboxRow {
407        margin: 0 0 20px 0;
408        width: 100%;
409      }
410      #mlb2-6731696.ml-form-embedContainer .ml-form-embedWrapper .ml-form-embedBody .ml-form-checkboxRow {
411        float: left;
412      }
413      #mlb2-6731696.ml-form-embedContainer .ml-form-embedWrapper .ml-form-embedBody .ml-form-formContent.horozintalForm {
414        margin: 0;
415        padding: 0 0 20px 0;
416        width: 100%;
417        height: auto;
418        float: left;
419      }
420      #mlb2-6731696.ml-form-embedContainer .ml-form-embedWrapper .ml-form-embedBody .ml-form-fieldRow {
421        margin: 0 0 10px 0;
422        width: 100%;
423      }
424      #mlb2-6731696.ml-form-embedContainer .ml-form-embedWrapper .ml-form-embedBody .ml-form-fieldRow.ml-last-item {
425        margin: 0;
426      }
427      #mlb2-6731696.ml-form-embedContainer .ml-form-embedWrapper .ml-form-embedBody .ml-form-fieldRow.ml-formfieldHorizintal {
428        margin: 0;
429      }
430      #mlb2-6731696.ml-form-embedContainer .ml-form-embedWrapper .ml-form-embedBody .ml-form-fieldRow input {
431        background-color: #ffffff !important;
432        color: #333333 !important;
433        border-color: #cccccc;
434        border-radius: 4px !important;
435        border-style: solid !important;
436        border-width: 1px !important;
437        font-family: 'Open Sans', Arial, Helvetica, sans-serif;
438        font-size: 12px !important;
439        height: auto;
440        line-height: 21px !important;
441        margin-bottom: 0;
442        margin-top: 0;
443        margin-left: 0;
444        margin-right: 0;
445        padding: 10px 10px !important;
446        width: 100% !important;
447        box-sizing: border-box !important;
448        max-width: 100% !important;
449      }
450      #mlb2-6731696.ml-form-embedContainer .ml-form-embedWrapper .ml-form-embedBody .ml-form-fieldRow input::-webkit-input-placeholder,
451      #mlb2-6731696.ml-form-embedContainer .ml-form-embedWrapper .ml-form-embedBody .ml-form-horizontalRow input::-webkit-input-placeholder { color: #333333; }
452
453      #mlb2-6731696.ml-form-embedContainer .ml-form-embedWrapper .ml-form-embedBody .ml-form-fieldRow input::-moz-placeholder,
454      #mlb2-6731696.ml-form-embedContainer .ml-form-embedWrapper .ml-form-embedBody .ml-form-horizontalRow input::-moz-placeholder { color: #333333; }
455
456      #mlb2-6731696.ml-form-embedContainer .ml-form-embedWrapper .ml-form-embedBody .ml-form-fieldRow input:-ms-input-placeholder,
457      #mlb2-6731696.ml-form-embedContainer .ml-form-embedWrapper .ml-form-embedBody .ml-form-horizontalRow input:-ms-input-placeholder { color: #333333; }
458
459      #mlb2-6731696.ml-form-embedContainer .ml-form-embedWrapper .ml-form-embedBody .ml-form-fieldRow input:-moz-placeholder,
460      #mlb2-6731696.ml-form-embedContainer .ml-form-embedWrapper .ml-form-embedBody .ml-form-horizontalRow input:-moz-placeholder { color: #333333; }
461
462      #mlb2-6731696.ml-form-embedContainer .ml-form-embedWrapper .ml-form-embedBody .ml-form-fieldRow textarea, #mlb2-6731696.ml-form-embedContainer .ml-form-embedWrapper .ml-form-embedBody .ml-form-horizontalRow textarea {
463        background-color: #ffffff !important;
464        color: #333333 !important;
465        border-color: #cccccc;
466        border-radius: 4px !important;
467        border-style: solid !important;
468        border-width: 1px !important;
469        font-family: 'Open Sans', Arial, Helvetica, sans-serif;
470        font-size: 12px !important;
471        height: auto;
472        line-height: 21px !important;
473        margin-bottom: 0;
474        margin-top: 0;
475        padding: 10px 10px !important;
476        width: 100% !important;
477        box-sizing: border-box !important;
478        max-width: 100% !important;
479      }
480
481      #mlb2-6731696.ml-form-embedContainer .ml-form-embedWrapper .ml-form-embedBody .ml-form-fieldRow .custom-radio .custom-control-label::before, #mlb2-6731696.ml-form-embedContainer .ml-form-embedWrapper .ml-form-embedBody .ml-form-horizontalRow .custom-radio .custom-control-label::before, #mlb2-6731696.ml-form-embedContainer .ml-form-embedWrapper .ml-form-embedBody .ml-form-fieldRow .custom-checkbox .custom-control-label::before, #mlb2-6731696.ml-form-embedContainer .ml-form-embedWrapper .ml-form-embedBody .ml-form-horizontalRow .custom-checkbox .custom-control-label::before, #mlb2-6731696.ml-form-embedContainer .ml-form-embedWrapper .ml-form-embedBody .ml-form-embedPermissions .ml-form-embedPermissionsOptionsCheckbox .label-description::before, #mlb2-6731696.ml-form-embedContainer .ml-form-embedWrapper .ml-form-embedBody .ml-form-interestGroupsRow .ml-form-interestGroupsRowCheckbox .label-description::before, #mlb2-6731696.ml-form-embedContainer .ml-form-embedWrapper .ml-form-embedBody .ml-form-checkboxRow .label-description::before {
482          border-color: #cccccc!important;
483          background-color: #ffffff!important;
484      }
485
486      #mlb2-6731696.ml-form-embedContainer .ml-form-embedWrapper .ml-form-embedBody .ml-form-fieldRow input.custom-control-input[type="checkbox"]{
487        box-sizing: border-box;
488        padding: 0;
489        position: absolute;
490        z-index: -1;
491        opacity: 0;
492        margin-top: 5px;
493        margin-left: -1.5rem;
494        overflow: visible;
495      }
496
497      #mlb2-6731696.ml-form-embedContainer .ml-form-embedWrapper .ml-form-embedBody .ml-form-fieldRow .custom-checkbox .custom-control-label::before, #mlb2-6731696.ml-form-embedContainer .ml-form-embedWrapper .ml-form-embedBody .ml-form-horizontalRow .custom-checkbox .custom-control-label::before, #mlb2-6731696.ml-form-embedContainer .ml-form-embedWrapper .ml-form-embedBody .ml-form-embedPermissions .ml-form-embedPermissionsOptionsCheckbox .label-description::before, #mlb2-6731696.ml-form-embedContainer .ml-form-embedWrapper .ml-form-embedBody .ml-form-interestGroupsRow .ml-form-interestGroupsRowCheckbox .label-description::before, #mlb2-6731696.ml-form-embedContainer .ml-form-embedWrapper .ml-form-embedBody .ml-form-checkboxRow .label-description::before {
498        border-radius: 4px!important;
499      }
500
501
502      #mlb2-6731696.ml-form-embedContainer .ml-form-embedWrapper .ml-form-embedBody .ml-form-checkboxRow input[type=checkbox]:checked~.label-description::after, #mlb2-6731696.ml-form-embedContainer .ml-form-embedWrapper .ml-form-embedBody .ml-form-embedPermissions .ml-form-embedPermissionsOptionsCheckbox input[type=checkbox]:checked~.label-description::after, #mlb2-6731696.ml-form-embedContainer .ml-form-embedWrapper .ml-form-embedBody .ml-form-fieldRow .custom-checkbox .custom-control-input:checked~.custom-control-label::after, #mlb2-6731696.ml-form-embedContainer .ml-form-embedWrapper .ml-form-embedBody .ml-form-horizontalRow .custom-checkbox .custom-control-input:checked~.custom-control-label::after, #mlb2-6731696.ml-form-embedContainer .ml-form-embedWrapper .ml-form-embedBody .ml-form-interestGroupsRow .ml-form-interestGroupsRowCheckbox input[type=checkbox]:checked~.label-description::after {
503        background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%23fff' d='M6.564.75l-3.59 3.612-1.538-1.55L0 4.26 2.974 7.25 8 2.193z'/%3e%3c/svg%3e");
504      }
505
506      #mlb2-6731696.ml-form-embedContainer .ml-form-embedWrapper .ml-form-embedBody .ml-form-fieldRow .custom-radio .custom-control-input:checked~.custom-control-label::after, #mlb2-6731696.ml-form-embedContainer .ml-form-embedWrapper .ml-form-embedBody .ml-form-fieldRow .custom-radio .custom-control-input:checked~.custom-control-label::after {
507        background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%23fff'/%3e%3c/svg%3e");
508      }
509
510      #mlb2-6731696.ml-form-embedContainer .ml-form-embedWrapper .ml-form-embedBody .ml-form-fieldRow .custom-radio .custom-control-input:checked~.custom-control-label::before, #mlb2-6731696.ml-form-embedContainer .ml-form-embedWrapper .ml-form-embedBody .ml-form-horizontalRow .custom-radio .custom-control-input:checked~.custom-control-label::before, #mlb2-6731696.ml-form-embedContainer .ml-form-embedWrapper .ml-form-embedBody .ml-form-fieldRow .custom-checkbox .custom-control-input:checked~.custom-control-label::before, #mlb2-6731696.ml-form-embedContainer .ml-form-embedWrapper .ml-form-embedBody .ml-form-horizontalRow .custom-checkbox .custom-control-input:checked~.custom-control-label::before, #mlb2-6731696.ml-form-embedContainer .ml-form-embedWrapper .ml-form-embedBody .ml-form-embedPermissions .ml-form-embedPermissionsOptionsCheckbox input[type=checkbox]:checked~.label-description::before, #mlb2-6731696.ml-form-embedContainer .ml-form-embedWrapper .ml-form-embedBody .ml-form-interestGroupsRow .ml-form-interestGroupsRowCheckbox input[type=checkbox]:checked~.label-description::before, #mlb2-6731696.ml-form-embedContainer .ml-form-embedWrapper .ml-form-embedBody .ml-form-checkboxRow input[type=checkbox]:checked~.label-description::before  {
511          border-color: #000000!important;
512          background-color: #000000!important;
513      }
514
515      #mlb2-6731696.ml-form-embedContainer .ml-form-embedWrapper .ml-form-embedBody .ml-form-fieldRow .custom-radio .custom-control-label::before, #mlb2-6731696.ml-form-embedContainer .ml-form-embedWrapper .ml-form-embedBody .ml-form-horizontalRow .custom-radio .custom-control-label::before, #mlb2-6731696.ml-form-embedContainer .ml-form-embedWrapper .ml-form-embedBody .ml-form-fieldRow .custom-radio .custom-control-label::after, #mlb2-6731696.ml-form-embedContainer .ml-form-embedWrapper .ml-form-embedBody .ml-form-horizontalRow .custom-radio .custom-control-label::after, #mlb2-6731696.ml-form-embedContainer .ml-form-embedWrapp
515er .ml-form-embedBody .ml-form-fieldRow .custom-checkbox .custom-control-label::before, #mlb2-6731696.ml-form-embedContainer .ml-form-embedWrapper .ml-form-embedBody .ml-form-fieldRow .custom-checkbox .custom-control-label::after, #mlb2-6731696.ml-form-embedContainer .ml-form-embedWrapper .ml-form-embedBody .ml-form-horizontalRow .custom-checkbox .custom-control-label::before, #mlb2-6731696.ml-form-embedContainer .ml-form-embedWrapper .ml-form-embedBody .ml-form-horizontalRow .custom-checkbox .custom-control-label::after {
516           top: 2px;
517           box-sizing: border-box;
518      }
519
520      #mlb2-6731696.ml-form-embedContainer .ml-form-embedWrapper .ml-form-embedBody .ml-form-embedPermissions .ml-form-embedPermissionsOptionsCheckbox .label-description::before, #mlb2-6731696.ml-form-embedContainer .ml-form-embedWrapper .ml-form-embedBody .ml-form-embedPermissions .ml-form-embedPermissionsOptionsCheckbox .label-description::after, #mlb2-6731696.ml-form-embedContainer .ml-form-embedWrapper .ml-form-embedBody .ml-form-checkboxRow .label-description::before, #mlb2-6731696.ml-form-embedContainer .ml-form-embedWrapper .ml-form-embedBody .ml-form-checkboxRow .label-description::after {
521           top: 0px!important;
522           box-sizing: border-box!important;
523      }
524
525      #mlb2-6731696.ml-form-embedContainer .ml-form-embedWrapper .ml-form-embedBody .ml-form-checkboxRow .label-description::before, #mlb2-6731696.ml-form-embedContainer .ml-form-embedWrapper .ml-form-embedBody .ml-form-checkboxRow .label-description::after {
526        top: 0px!important;
527           box-sizing: border-box!important;
528      }
529
530       #mlb2-6731696.ml-form-embedContainer .ml-form-embedWrapper .ml-form-embedBody .ml-form-interestGroupsRow .ml-form-interestGroupsRowCheckbox .label-description::after {
531            top: 0px!important;
532            box-sizing: border-box!important;
533            position: absolute;
534            left: -1.5rem;
535            display: block;
536            width: 1rem;
537            height: 1rem;
538            content: "";
539       }
540
541      #mlb2-6731696.ml-form-embedContainer .ml-form-embedWrapper .ml-form-embedBody .ml-form-interestGroupsRow .ml-form-interestGroupsRowCheckbox .label-description::before {
542        top: 0px!important;
543        box-sizing: border-box!important;
544      }
545
546      #mlb2-6731696.ml-form-embedContainer .ml-form-embedWrapper .ml-form-embedBody .custom-control-label::before {
547          position: absolute;
548          top: 4px;
549          left: -1.5rem;
550          display: block;
551          width: 16px;
552          height: 16px;
553          pointer-events: none;
554          content: "";
555          background-color: #ffffff;
556          border: #adb5bd solid 1px;
557          border-radius: 50%;
558      }
559
560      #mlb2-6731696.ml-form-embedContainer .ml-form-embedWrapper .ml-form-embedBody .custom-control-label::after {
561          position: absolute;
562          top: 2px!important;
563          left: -1.5rem;
564          display: block;
565          width: 1rem;
566          height: 1rem;
567          content: "";
568      }
569
570      #mlb2-6731696.ml-form-embedContainer .ml-form-embedWrapper .ml-form-embedBody .ml-form-embedPermissions .ml-form-embedPermissionsOptionsCheckbox .label-description::before, #mlb2-6731696.ml-form-embedContainer .ml-form-embedWrapper .ml-form-embedBody .ml-form-interestGroupsRow .ml-form-interestGroupsRowCheckbox .label-description::before, #mlb2-6731696.ml-form-embedContainer .ml-form-embedWrapper .ml-form-embedBody .ml-form-checkboxRow .label-description::before {
571          position: absolute;
572          top: 4px;
573          left: -1.5rem;
574          display: block;
575          width: 16px;
576          height: 16px;
577          pointer-events: none;
578          content: "";
579          background-color: #ffffff;
580          border: #adb5bd solid 1px;
581          border-radius: 50%;
582      }
583
584      #mlb2-6731696.ml-form-embedContainer .ml-form-embedWrapper .ml-form-embedBody .ml-form-embedPermissions .ml-form-embedPermissionsOptionsCheckbox .label-description::after {
585          position: absolute;
586          top: 0px!important;
587          left: -1.5rem;
588          display: block;
589          width: 1rem;
590          height: 1rem;
591          content: "";
592      }
593
594      #mlb2-6731696.ml-form-embedContainer .ml-form-embedWrapper .ml-form-embedBody .ml-form-checkboxRow .label-description::after {
595          position: absolute;
596          top: 0px!important;
597          left: -1.5rem;
598          display: block;
599          width: 1rem;
600          height: 1rem;
601          content: "";
602      }
603
604      #mlb2-6731696.ml-form-embedContainer .ml-form-embedWrapper .ml-form-embedBody .custom-radio .custom-control-label::after {
605          background: no-repeat 50%/50% 50%;
606      }
607      #mlb2-6731696.ml-form-embedContainer .ml-form-embedWrapper .ml-form-embedBody .custom-checkbox .custom-control-label::after, #mlb2-6731696.ml-form-embedContainer .ml-form-embedWrapper .ml-form-embedBody .ml-form-embedPermissions .ml-form-embedPermissionsOptionsCheckbox .label-description::after, #mlb2-6731696.ml-form-embedContainer .ml-form-embedWrapper .ml-form-embedBody .ml-form-interestGroupsRow .ml-form-interestGroupsRowCheckbox .label-description::after, #mlb2-6731696.ml-form-embedContainer .ml-form-embedWrapper .ml-form-embedBody .ml-form-checkboxRow .label-description::after {
608          background: no-repeat 50%/50% 50%;
609      }
610
611      #mlb2-6731696.ml-form-embedContainer .ml-form-embedWrapper .ml-form-embedBody .ml-form-fieldRow .custom-control, #mlb2-6731696.ml-form-embedContainer .ml-form-embedWrapper .ml-form-embedBody .ml-form-horizontalRow .custom-control {
612        position: relative;
613        display: block;
614        min-height: 1.5rem;
615        padding-left: 1.5rem;
616      }
617
618      #mlb2-6731696.ml-form-embedContainer .ml-form-embedWrapper .ml-form-embedBody .ml-form-fieldRow .custom-radio .custom-control-input, #mlb2-6731696.ml-form-embedContainer .ml-form-embedWrapper .ml-form-embedBody .ml-form-horizontalRow .custom-radio .custom-control-input, #mlb2-6731696.ml-form-embedContainer .ml-form-embedWrapper .ml-form-embedBody .ml-form-fieldRow .custom-checkbox .custom-control-input, #mlb2-6731696.ml-form-embedContainer .ml-form-embedWrapper .ml-form-embedBody .ml-form-horizontalRow .custom-checkbox .custom-control-input {
619          position: absolute;
620          z-index: -1;
621          opacity: 0;
622          box-sizing: border-box;
623          padding: 0;
624      }
625
626      #mlb2-6731696.ml-form-embedContainer .ml-form-embedWrapper .ml-form-embedBody .ml-form-fieldRow .custom-radio .custom-control-label, #mlb2-6731696.ml-form-embedContainer .ml-form-embedWrapper .ml-form-embedBody .ml-form-horizontalRow .custom-radio .custom-control-label, #mlb2-6731696.ml-form-embedContainer .ml-form-embedWrapper .ml-form-embedBody .ml-form-fieldRow .custom-checkbox .custom-control-label, #mlb2-6731696.ml-form-embedContainer .ml-form-embedWrapper .ml-form-embedBody .ml-form-horizontalRow .custom-checkbox .custom-control-label {
627          color: #000000;
628          font-size: 12px!important;
629          font-family: 'Open Sans', Arial, Helvetica, sans-serif;
630          line-height: 22px;
631          margin-bottom: 0;
632          position: relative;
633          vertical-align: top;
634          font-style: normal;
635          font-weight: 700;
636      }
637
638      #mlb2-6731696.ml-form-embedContainer .ml-form-embedWrapper .ml-form-embedBody .ml-form-fieldRow .custom-select, #mlb2-6731696.ml-form-embedContainer .ml-form-embedWrapper .ml-form-embedBody .ml-form-horizontalRow .custom-select {
639        background-color: #ffffff !important;
640        color: #333333 !important;
641        border-color: #cccccc;
642        border-radius: 4px !important;
643        border-style: solid !important;
644        border-width: 1px !important;
645        font-family: 'Open Sans', Arial, Helvetica, sans-serif;
646        font-size: 12px !important;
647        line-height: 20px !important;
648        margin-bottom: 0;
649        margin-top: 0;
650        padding: 10px 28px 10px 12px !important;
651        width: 100% !important;
652        box-sizing: border-box !important;
653        max-width: 100% !important;
654        height: auto;
655        display: inline-block;
656        vertical-align: middle;
657        background: url('https://assets.mlcdn.com/ml/images/default/dropdown.svg') no-repeat right .75rem center/8px 10px;
658        -webkit-appearance: none;
659        -moz-appearance: none;
660        appearance: none;
661      }
662
663
664      #mlb2-6731696.ml-form-embedContainer .ml-form-embedWrapper .ml-form-embedBody .ml-form-horizontalRow {
665        height: auto;
666        width: 100%;
667        float: left;
668      }
669      .ml-form-formContent.horozintalForm .ml-form-horizontalRow .ml-input-horizontal { width: 70%; float: left; }
670      .ml-form-formContent.horozintalForm .ml-form-horizontalRow .ml-button-horizontal { width: 30%; float: left; }
671      .ml-form-formContent.horozintalForm .ml-form-horizontalRow .ml-button-horizontal.labelsOn { padding-top: 25px;  }
672      .ml-form-formContent.horozintalForm .ml-form-horizontalRow .horizontal-fields { box-sizing: border-box; float: left; padding-right: 10px;  }
673      #mlb2-6731696.ml-form-embedContainer .ml-form-embedWrapper .ml-form-embedBody .ml-form-horizontalRow input {
674        background-color: #ffffff;
675        color: #333333;
676        border-color: #cccccc;
677        border-radius: 4px;
678        border-style: solid;
679        border-width: 1px;
680        font-family: 'Open Sans', Arial, Helvetica, sans-serif;
681        font-size: 12px;
682        line-height: 20px;
683        margin-bottom: 0;
684        margin-top: 0;
685        padding: 10px 10px;
686        width: 100%;
687        box-sizing: border-box;
688        overflow-y: initial;
689      }
690      #mlb2-6731696.ml-form-embedContainer .ml-form-embedWrapper .ml-form-embedBody .ml-form-horizontalRow button {
691        background-color: #000000 !important;
692        border-color: #000000;
693        border-style: solid;
694        border-width: 1px;
695        border-radius: 4px;
696        box-shadow: none;
697        color: #ffffff !important;
698        cursor: pointer;
699        font-family: 'Raleway', sans-serif;
700        font-size: 14px !important;
701        font-weight: 700;
702        line-height: 20px;
703        margin: 0 !important;
704        padding: 10px !important;
705        width: 100%;
706        height: auto;
707      }
708      #mlb2-6731696.ml-form-embedContainer .ml-form-embedWrapper .ml-form-embedBody .ml-form-horizontalRow button:hover {
709        background-color: #333333 !important;
710        border-color: #333333 !important;
711      }
712      #mlb2-6731696.ml-form-embedContainer .ml-form-embedWrapper .ml-form-embedBody .ml-form-checkboxRow input[type="checkbox"] {
713        box-sizing: border-box;
714        padding: 0;
715        position: absolute;
716        z-index: -1;
717        opacity: 0;
718        margin-top: 5px;
719        margin-left: -1.5rem;
720        overflow: visible;
721      }
722      #mlb2-6731696.ml-form-embedContainer .ml-form-embedWrapper .ml-form-embedBody .ml-form-checkboxRow .label-description {
723        color: #000000;
724        display: block;
725        font-family: 'Open Sans', Arial, Helvetica, sans-serif;
726        font-size: 12px;
727        text-align: left;
728        margin-bottom: 0;
729        position: relative;
730        vertical-align: top;
731      }
732      #mlb2-6731696.ml-form-embedContainer .ml-form-embedWrapper .ml-form-embedBody .ml-form-checkboxRow label {
733        font-weight: normal;
734        margin: 0;
735        padding: 0;
736        position: relative;
737        display: block;
738        min-height: 24px;
739        padding-left: 24px;
740
741      }
742      #mlb2-6731696.ml-form-embedContainer .ml-form-embedWrapper .ml-form-embedBody .ml-form-checkboxRow label a {
743        color: #000000;
744        text-decoration: underline;
745      }
746      #mlb2-6731696.ml-form-embedContainer .ml-form-embedWrapper .ml-form-embedBody .ml-form-checkboxRow label p {
747        color: #000000 !important;
748        font-family: 'Open Sans', Arial, Helvetica, sans-serif !important;
749        font-size: 12px !important;
750        font-weight: normal !important;
751        line-height: 18px !important;
752        padding: 0 !important;
753        margin: 0 5px 0 0 !important;
754      }
755      #mlb2-6731696.ml-form-embedContainer .ml-form-embedWrapper .ml-form-embedBody .ml-form-checkboxRow label p:last-child {
756        margin: 0;
757      }
758      #mlb2-6731696.ml-form-embedContainer .ml-form-embedWrapper .ml-form-embedBody .ml-form-embedSubmit {
759        margin: 0 0 20px 0;
760        float: left;
761        width: 100%;
762      }
763      #mlb2-6731696.ml-form-embedContainer .ml-form-embedWrapper .ml-form-embedBody .ml-form-embedSubmit button {
764        background-color: #000000 !important;
765        border: none !important;
766        border-radius: 4px !important;
767        box-shadow: none !important;
768        color: #ffffff !important;
769        cursor: pointer;
770        font-family: 'Raleway', sans-serif !important;
771        font-size: 14px !important;
772        font-weight: 700 !important;
773        line-height: 21px !important;
774        height: auto;
775        padding: 10px !important;
776        width: 100% !important;
777        box-sizing: border-box !important;
778      }
779      #mlb2-6731696.ml-form-embedContainer .ml-form-embedWrapper .ml-form-embedBody .ml-form-embedSubmit button.loading {
780        display: none;
781      }
782      #mlb2-6731696.ml-form-embedContainer .ml-form-embedWrapper .ml-form-embedBody .ml-form-embedSubmit button:hover {
783        background-color: #333333 !important;
784      }
785      .ml-subscribe-close {
786        width: 30px;
787        height: 30px;
788        background: url('https://assets.mlcdn.com/ml/images/default/modal_
788close.png') no-repeat;
789        background-size: 30px;
790        cursor: pointer;
791        margin-top: -10px;
792        margin-right: -10px;
793        position: absolute;
794        top: 0;
795        right: 0;
796      }
797      .ml-error input, .ml-error textarea, .ml-error select {
798        border-color: red!important;
799      }
800
801      .ml-error .custom-checkbox-radio-list {
802        border: 1px solid red !important;
803        border-radius: 4px;
804        padding: 10px;
805      }
806
807      .ml-error .label-description,
808      .ml-error .label-description p,
809      .ml-error .label-description p a,
810      .ml-error label:first-child {
811        color: #ff0000 !important;
812      }
813
814      #mlb2-6731696.ml-form-embedContainer .ml-form-embedWrapper .ml-form-embedBody .ml-form-checkboxRow.ml-error .label-description p,
815      #mlb2-6731696.ml-form-embedContainer .ml-form-embedWrapper .ml-form-embedBody .ml-form-checkboxRow.ml-error .label-description p:first-letter {
816        color: #ff0000 !important;
817      }
818            @media only screen and (max-width: 410px){
819
820        .ml-form-embedWrapper.embedDefault, .ml-form-embedWrapper.embedPopup { width: 100%!important; }
821        .ml-form-formContent.horozintalForm { float: left!important; }
822        .ml-form-formContent.horozintalForm .ml-form-horizontalRow { height: auto!important; width: 100%!important; float: left!important; }
823        .ml-form-formContent.horozintalForm .ml-form-horizontalRow .ml-input-horizontal { width: 100%!important; }
824        .ml-form-formContent.horozintalForm .ml-form-horizontalRow .ml-input-horizontal > div { padding-right: 0px!important; padding-bottom: 10px; }
825        .ml-form-formContent.horozintalForm .ml-button-horizontal { width: 100%!important; }
826        .ml-form-formContent.horozintalForm .ml-button-horizontal.labelsOn { padding-top: 0px!important; }
827
828      }
829    </style>
830
831    
832  
833    
834    
835
836    
837    
838
839    
840    
841
842    
843
844      
845        
846        
847      
848
849      
850        
851        
852      
853
854      
855
856            
857            
858            
859            
860            
861            
862      
863
864      
865
866      
867        
868        
869         
870        
871        
872      
873
874        
875        
876        
877        
878        
879        
880      
881
882       
883
884        
885        
886        
887        
888        
889        
890        
891       
892
893
894      
895        
896        
897        
898        
899  
900
901
902
903  
904        
905        
906        
907      
908
909
910      
911    
912    
913    
914    
915    
916    
917    
918  
919
920  
921        
922        
923        
924        
925        
926      
927
928      
929        
930        
931        
932        
933        
934      
935
936      
937        
938        
939        
940        
941        
942      
943
944       
945
946        
947        
948        
949        
950       
951
952       
953        
954        
955        
956        
957      
958
959      
960        
961        
962        
963        
964        
965        
966        
967       
968
969    
970
971    
972
973
974      
975
976
977      
978
979      
980      
981
982      
983
984      
985
986
987
988
989
990    
991
992      
993    <div id="mlb2-6731696" class="ml-form-embedContainer ml-subscribe-form ml-subscribe-form-6731696">
994      <div class="ml-form-align-center ">
995        <div class="ml-form-embedWrapper embedForm">
996
997          
998          
999
1000          <div class="ml-form-embedBody ml-form-embedBodyDefault row-form">
1001
1002            <div class="ml-form-embedContent" style=" ">
1003              
1004                <h4>Get access to new courses, special discounts and exclusive content</h4>
1005                <p>Welcome email includes discounts on all current courses</p>
1006<p></p>
1007              
1008            </div>
1009
1010            <form class="ml-block-form" action="https://assets.mailerlite.com/jsonp/536330/forms/95327619316189111/subscribe" data-code="" method="post" target="_blank">
1011              <div class="ml-form-formContent">
1012                
1013
1014                  
1015                  <div class="ml-form-fieldRow ml-last-item">
1016                    <div class="ml-field-group ml-field-email ml-validate-email ml-validate-required">
1017
1018                      
1019
1020
1021                      <!-- input -->
1022                      <input aria-label="email" aria-required="true" type="email" class="form-control" data-inputmask="" name="fields[email]" placeholder="Email" autocomplete="email">
1023                      <!-- /input -->
1024
1025                      <!-- textarea -->
1026                      
1027                      <!-- /textarea -->
1028
1029                      <!-- select -->
1030                      
1031                      <!-- /select -->
1032
1033                      <!-- checkboxes -->
1034            
1035            <!-- /checkboxes -->
1036
1037                      <!-- radio -->
1038                      
1039                      <!-- /radio -->
1040
1041                      <!-- countries -->
1042                      
1043                      <!-- /countries -->
1044
1045
1046
1047
1048
1049                    </div>
1050                  </div>
1051                
1052              </div>
1053
1054              
1055
1056              <!-- Privacy policy -->
1057              
1058              <!-- /Privacy policy -->
1059
1060              
1061
1062              
1063
1064              
1065
1066
1067
1068
1069
1070
1071              
1072              <input type="hidden" name="ml-submit" value="1">
1073
1074              <div class="ml-form-embedSubmit">
1075                
1076                  <button type="submit" class="primary">Get access</button>
1077                
1078                <button disabled="disabled" style="display: none;" type="button" class="loading">
1079                  <div class="ml-form-embedSubmitLoad"></div>
1080                  <span class="sr-only">Loading...</span>
1081                </button>
1082              </div>
1083
1084              
1085              <input type="hidden" name="anticsrf" value="true">
1086            </form>
1087          </div>
1088
1089          <div class="ml-form-successBody row-success" style="display: none">
1090
1091            <div class="ml-form-successContent">
1092              
1093                <h4>Thank you!</h4>
1094                <p>You have successfully joined the subscriber list.</p>
1095              
1096            </div>
1097
1098          </div>
1099        </div>
1100      </div>
1101    </div>
1102
1103  
1104
1105  
1106  
1107  
1107<script>
1108    function ml_webform_success_6731696() {
1109      var $ = ml_jQuery || jQuery;
1110      $('.ml-subscribe-form-6731696 .row-success').show();
1111      $('.ml-subscribe-form-6731696 .row-form').hide();
1112    }
1113      </script>
1113
1114  
1115  
1116      
1116<script src="https://groot.mailerlite.com/js/w/webforms.min.js?v1f25ee4b05f240a833e02c19975434a4" type="text/javascript"></script>
1116
1117        
1117<script>
1118            fetch("https://assets.mailerlite.com/jsonp/536330/forms/95327619316189111/track-view")
1119        </script>
1119
1120<p><br><br></p>
1121</section>
1122</section>
1123</div>
1124<div class="g-col-2">
1125
1126</div>
1127</div>
1128</center>
1129
1130
1131
1132
1133
1134<script id="quarto-html-after-body" type="application/javascript">
1135  window.document.addEventListener("DOMContentLoaded", function (event) {
1136    const isCodeAnnotation = (el) => {
1137      for (const clz of el.classList) {
1138        if (clz.startsWith('code-annotation-')) {                     
1139          return true;
1140        }
1141      }
1142      return false;
1143    }
1144    const onCopySuccess = function(e) {
1145      // button target
1146      const button = e.trigger;
1147      // don't keep focus
1148      button.blur();
1149      // flash "checked"
1150      button.classList.add('code-copy-button-checked');
1151      var currentTitle = button.getAttribute("title");
1152      button.setAttribute("title", "Copied!");
1153      let tooltip;
1154      if (window.bootstrap) {
1155        button.setAttribute("data-bs-toggle", "tooltip");
1156        button.setAttribute("data-bs-placement", "left");
1157        button.setAttribute("data-bs-title", "Copied!");
1158        tooltip = new bootstrap.Tooltip(button, 
1159          { trigger: "manual", 
1160            customClass: "code-copy-button-tooltip",
1161            offset: [0, -8]});
1162        tooltip.show();    
1163      }
1164      setTimeout(function() {
1165        if (tooltip) {
1166          tooltip.hide();
1167          button.removeAttribute("data-bs-title");
1168          button.removeAttribute("data-bs-toggle");
1169          button.removeAttribute("data-bs-placement");
1170        }
1171        button.setAttribute("title", currentTitle);
1172        button.classList.remove('code-copy-button-checked');
1173      }, 1000);
1174      // clear code selection
1175      e.clearSelection();
1176    }
1177    const getTextToCopy = function(trigger) {
1178        const codeEl = trigger.previousElementSibling.cloneNode(true);
1179        for (const childEl of codeEl.children) {
1180          if (isCodeAnnotation(childEl)) {
1181            childEl.remove();
1182          }
1183        }
1184        return codeEl.innerText;
1185    }
1186    const clipboard = new window.ClipboardJS('.code-copy-button:not([data-in-quarto-modal])', {
1187      text: getTextToCopy
1188    });
1189    clipboard.on('success', onCopySuccess);
1190    if (window.document.getElementById('quarto-embedded-source-code-modal')) {
1191      const clipboardModal = new window.ClipboardJS('.code-copy-button[data-in-quarto-modal]', {
1192        text: getTextToCopy,
1193        container: window.document.getElementById('quarto-embedded-source-code-modal')
1194      });
1195      clipboardModal.on('success', onCopySuccess);
1196    }
1197      var localhostRegex = new RegExp(/^(?:http|https):\/\/localhost\:?[0-9]*\//);
1198      var mailtoRegex = new RegExp(/^mailto:/);
1199        var filterRegex = new RegExp("https:\/\/xpsong\.com");
1200      var isInternal = (href) => {
1201          return filterRegex.test(href) || localhostRegex.test(href) || mailtoRegex.test(href);
1202      }
1203      // Inspect non-navigation links and adorn them if external
1204     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)');
1205      for (var i=0; i<links.length; i++) {
1206        const link = links[i];
1207        if (!isInternal(link.href)) {
1208          // undo the damage that might have been done by quarto-nav.js in the case of
1209          // links that we want to consider external
1210          if (link.dataset.originalHref !== undefined) {
1211            link.href = link.dataset.originalHref;
1212          }
1213        }
1214      }
1215    function tippyHover(el, contentFn, onTriggerFn, onUntriggerFn) {
1216      const config = {
1217        allowHTML: true,
1218        maxWidth: 500,
1219        delay: 100,
1220        arrow: false,
1221        appendTo: function(el) {
1222            return el.parentElement;
1223        },
1224        interactive: true,
1225        interactiveBorder: 10,
1226        theme: 'quarto',
1227        placement: 'bottom-start',
1228      };
1229      if (contentFn) {
1230        config.content = contentFn;
1231      }
1232      if (onTriggerFn) {
1233        config.onTrigger = onTriggerFn;
1234      }
1235      if (onUntriggerFn) {
1236        config.onUntrigger = onUntriggerFn;
1237      }
1238      window.tippy(el, config); 
1239    }
1240    const noterefs = window.document.querySelectorAll('a[role="doc-noteref"]');
1241    for (var i=0; i<noterefs.length; i++) {
1242      const ref = noterefs[i];
1243      tippyHover(ref, function() {
1244        // use id or data attribute instead here
1245        let href = ref.getAttribute('data-footnote-href') || ref.getAttribute('href');
1246        try { href = new URL(href).hash; } catch {}
1247        const id = href.replace(/^#\/?/, "");
1248        const note = window.document.getElementById(id);
1249        if (note) {
1250          return note.innerHTML;
1251        } else {
1252          return "";
1253        }
1254      });
1255    }
1256    const xrefs = window.document.querySelectorAll('a.quarto-xref');
1257    const processXRef = (id, note) => {
1258      // Strip column container classes
1259      const stripColumnClz = (el) => {
1260        el.classList.remove("page-full", "page-columns");
1261        if (el.children) {
1262          for (const child of el.children) {
1263            stripColumnClz(child);
1264          }
1265        }
1266      }
1267      stripColumnClz(note)
1268      if (id === null || id.startsWith('sec-')) {
1269        // Special case sections, only their first couple elements
1270        const container = document.createElement("div");
1271        if (note.children && note.children.length > 2) {
1272          container.appendChild(note.children[0].cloneNode(true));
1273          for (let i = 1; i < note.children.length; i++) {
1274            const child = note.children[i];
1275            if (child.tagName === "P" && child.innerText === "") {
1276              continue;
1277            } else {
1278              container.appendChild(child.cloneNode(true));
1279              break;
1280            }
1281          }
1282          if (window.Quarto?.typesetMath) {
1283            window.Quarto.typesetMath(container);
1284          }
1285          return container.innerHTML
1286        } else {
1287          if (window.Quarto?.typesetMath) {
1288            window.Quarto.typesetMath(note);
1289          }
1290          return note.innerHTML;
1291        }
1292      } else {
1293        // Remove any anchor links if they are present
1294        const anchorLink = note.querySelector('a.anchorjs-link');
1295        if (anchorLink) {
1296          anchorLink.remove();
1297        }
1298        if (window.Quarto?.typesetMath) {
1299          window.Quarto.typesetMath(note);
1300        }
1301        if (note.classList.contains("callout")) {
1302          return note.outerHTML;
1303        } else {
1304          return note.innerHTML;
1305        }
1306      }
1307    }
1308    for (var i=0; i<xrefs.length; i++) {
1309      const xref = xrefs[i];
1310      tippyHover(xref, undefined, function(instance) {
1311        instance.disable();
1312        let url = xref.getAttribute('href');
1313        let hash = undefined; 
1314        if (url.startsWith('#')) {
1315          hash = url;
1316        } else {
1317          try { hash = new URL(url).hash; } catch {}
1318        }
1319        if (hash) {
1320          const id = hash.replace(/^#\/?/, "");
1321          const note = window.document.getElementById(id);
1322          if (note !== null) {
1323            try {
1324              const html = processXRef(id, note.cloneNode(true));
1325              instance.setContent(html);
1326            } finally {
1327              instance.enable();
1328              instance.show();
1329            }
1330          } else {
1331            // See if we can fetch this
1332            fetch(url.split('#')[0])
1333            .then(res => res.text())
1334            .then(html => {
1335              const parser = new DOMParser();
1336              const htmlDoc = parser.parseFromString(html, "text/html");
1337              const note = htmlDoc.getElementById(id);
1338              if (note !== null) {
1339                const html = processXRef(id, note);
1340                instance.setContent(html);
1341              } 
1342            }).finally(() => {
1343              instance.enable();
1344              instance.show();
1345            });
1346          }
1347        } else {
1348          // See if we can fetch a full url (with no hash to target)
1349          // This is a special case and we should probably do some content thinning / targeting
1350          fetch(url)
1351          .then(res => res.text())
1352          .then(html => {
1353            const parser = new DOMParser();
1354            const htmlDoc = parser.parseFromString(html, "text/html");
1355            const note = htmlDoc.querySelector('main.content');
1356            if (note !== null) {
1357              // This should only happen for chapter cross references
1358              // (since there is no id in the URL)
1359              // remove the first header
1360              if (note.children.length > 0 && note.children[0].tagName === "HEADER") {
1361                note.children[0].remove();
1362              }
1363              const html = processXRef(null, note);
1364              instance.setContent(html);
1365            } 
1366          }).finally(() => {
1367            instance.enable();
1368            instance.show();
1369          });
1370        }
1371      }, function(instance) {
1372      });
1373    }
1374        let selectedAnnoteEl;
1375        const selectorForAnnotation = ( cell, annotation) => {
1376          let cellAttr = 'data-code-cell="' + cell + '"';
1377          let lineAttr = 'data-code-annotation="' +  annotation + '"';
1378          const selector = 'span[' + cellAttr + '][' + lineAttr + ']';
1379          return selector;
1380        }
1381        const selectCodeLines = (annoteEl) => {
1382          const doc = window.document;
1383          const targetCell = annoteEl.getAttribute("data-target-cell");
1384          const targetAnnotation = annoteEl.getAttribute("data-target-annotation");
1385          const annoteSpan = window.document.querySelector(selectorForAnnotation(targetCell, targetAnnotation));
1386          const lines = annoteSpan.getAttribute("data-code-lines").split(",");
1387          const lineIds = lines.map((line) => {
1388            return targetCell + "-" + line;
1389          })
1390          let top = null;
1391          let height = null;
1392          let parent = null;
1393          if (lineIds.length > 0) {
1394              //compute the position of the single el (top and bottom and make a div)
1395              const el = window.document.getElementById(lineIds[0]);
1396              top = el.offsetTop;
1397              height = el.offsetHeight;
1398              parent = el.parentElement.parentElement;
1399            if (lineIds.length > 1) {
1400              const lastEl = window.document.getElementById(lineIds[lineIds.length - 1]);
1401              const bottom = lastEl.offsetTop + lastEl.offsetHeight;
1402              height = bottom - top;
1403            }
1404            if (top !== null && height !== null && parent !== null) {
1405              // cook up a div (if necessary) and position it 
1406              let div = window.document.getElementById("code-annotation-line-highlight");
1407              if (div === null) {
1408                div = window.document.createElement("div");
1409                div.setAttribute("id", "code-annotation-line-highlight");
1410                div.style.position = 'absolute';
1411                parent.appendChild(div);
1412              }
1413              div.style.top = top - 2 + "px";
1414              div.style.height = height + 4 + "px";
1415              div.style.left = 0;
1416              let gutterDiv = window.document.getElementById("code-annotation-line-highlight-gutter");
1417              if (gutterDiv === null) {
1418                gutterDiv = window.document.createElement("div");
1419                gutterDiv.setAttribute("id", "code-annotation-line-highlight-gutter");
1420                gutterDiv.style.position = 'absolute';
1421                const codeCell = window.document.getElementById(targetCell);
1422                const gutter = codeCell.querySelector('.code-annotation-gutter');
1423                gutter.appendChild(gutterDiv);
1424              }
1425              gutterDiv.style.top = top - 2 + "px";
1426              gutterDiv.style.height = height + 4 + "px";
1427            }
1428            selectedAnnoteEl = annoteEl;
1429          }
1430        };
1431        const unselectCodeLines = () => {
1432          const elementsIds = ["code-annotation-line-highlight", "code-annotation-line-highlight-gutter"];
1433          elementsIds.forEach((elId) => {
1434            const div = window.document.getElementById(elId);
1435            if (div) {
1436              div.remove();
1437            }
1438          });
1439          selectedAnnoteEl = undefined;
1440        };
1441          // Handle positioning of the toggle
1442      window.addEventListener(
1443        "resize",
1444        throttle(() => {
1445          elRect = undefined;
1446          if (selectedAnnoteEl) {
1447            selectCodeLines(selectedAnnoteEl);
1448          }
1449        }, 10)
1450      );
1451      function throttle(fn, ms) {
1452      let throttle = false;
1453      let timer;
1454        return (...args) => {
1455          if(!throttle) { // first call gets through
1456              fn.apply(this, args);
1457              throttle = true;
1458          } else { // all the others get throttled
1459              if(timer) clearTimeout(timer); // cancel #2
1460              timer = setTimeout(() => {
1461                fn.apply(this, args);
1462                timer = throttle = false;
1463              }, ms);
1464          }
1465        };
1466      }
1467        // Attach click handler to the DT
1468        const annoteDls = window.document.querySelectorAll('dt[data-target-cell]');
1469        for (const annoteDlNode of annoteDls) {
1470          annoteDlNode.addEventListener('click', (event) => {
1471            const clickedEl = event.target;
1472            if (clickedEl !== selectedAnnoteEl) {
1473              unselectCodeLines();
1474              const activeEl = window.document.querySelector('dt[data-target-cell].code-annotation-active');
1475              if (activeEl) {
1476                activeEl.classList.remove('code-annotation-active');
1477              }
1478              selectCodeLines(clickedEl);
1479              clickedEl.classList.add('code-annotation-active');
1480            } else {
1481              // Unselect the line
1482              unselectCodeLines();
1483              clickedEl.classList.remove('code-annotation-active');
1484            }
1485          });
1486        }
1487    const findCites = (el) => {
1488      const parentEl = el.parentElement;
1489      if (parentEl) {
1490        const cites = parentEl.dataset.cites;
1491        if (cites) {
1492          return {
1493            el,
1494            cites: cites.split(' ')
1495          };
1496        } else {
1497          return findCites(el.parentElement)
1498        }
1499      } else {
1500        return undefined;
1501      }
1502    };
1503    var bibliorefs = window.document.querySelectorAll('a[role="doc-biblioref"]');
1504    for (var i=0; i<bibliorefs.length; i++) {
1505      const ref = bibliorefs[i];
1506      const citeInfo = findCites(ref);
1507      if (citeInfo) {
1508        tippyHover(citeInfo.el, function() {
1509          var popup = window.document.createElement('div');
1510          citeInfo.cites.forEach(function(cite) {
1511            var citeDiv = window.document.createElement('div');
1512            citeDiv.classList.add('hanging-indent');
1513            citeDiv.classList.add('csl-entry');
1514            var biblioDiv = window.document.getElementById('ref-' + cite);
1515            if (biblioDiv) {
1516              citeDiv.innerHTML = biblioDiv.innerHTML;
1517            }
1518            popup.appendChild(citeDiv);
1519          });
1520          return popup.innerHTML;
1521        });
1522      }
1523    }
1524  });
1525  </script>
1525
1526</div> <!-- /content -->
1527<footer class="footer">
1528  <div class="nav-footer">
1529    <div class="nav-footer-left">
1530<p>© 2026 XP Song. Built with <a href="https://quarto.org/">Quarto</a>.</p>
1531</div>   
1532    <div class="nav-footer-center">
1533      &nbsp;
1534    </div>
1535    <div class="nav-footer-right">
1536      <ul class="footer-items list-unstyled">
1537    <li class="nav-item">
1538    <a class="nav-link" href="mailto:[email protected]">
1539<p>Contact</p>
1540</a>
1541  </li>  
1542    <li class="nav-item">
1543    <a class="nav-link" href="https://creativecommons.org/licenses/by-sa/4.0/">
1544<p>License</p>
1545</a>
1546  </li>  
1547    <li class="nav-item">
1548    <a class="nav-link" href="./blog.xml">
1549<p>RSS</p>
1550</a>
1551  </li>  
1552</ul>
1553    </div>
1554  </div>
1555</footer>
1556
1557
1558
1559
1560</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.