PageSourceSearch

https://dyob.ca/stretch-yoga/

html dyob.ca collected 2026-10-04 08:02:47 UTC 24,516 bytes, 689 lines download raw bytes

1<!DOCTYPE html>
2<html lang="en">
3<head>
4    <meta charset="utf-8">
5    <meta name="viewport" content="width=device-width, initial-scale=1.0">
6    <title>Yoga</title>
7    <link rel="canonical" href="https://www.dyob.ca/stretch-yoga/">
8    <meta name="referrer" content="no-referrer-when-downgrade">
9    
10    <meta property="og:site_name" content="Boyd Thomson">
11    <meta property="og:type" content="website">
12    <meta property="og:title" content="Yoga">
13    <meta property="og:description" content="Boyd is a founder of STRETCH, Vancouver&#x27;s favourite Chinatown studio for yoga and events.">
14    <meta property="og:url" content="https://www.dyob.ca/stretch-yoga/">
15    <meta property="og:image" content="https://www.dyob.ca/content/images/size/w1200/2024/11/amcl-july-19-2023338_53069923140-1.jpg">
16    <meta property="article:published_time" content="2024-11-06T19:04:34.000Z">
17    <meta property="article:modified_time" content="2026-05-25T00:21:52.000Z">
18    <meta property="article:publisher" content="https://www.facebook.com/yoga.nerd.vancouver">
19    <meta name="twitter:card" content="summary_large_image">
20    <meta name="twitter:title" content="Yoga">
21    <meta name="twitter:description" content="Boyd is a founder of STRETCH, Vancouver&#x27;s favourite Chinatown studio for yoga and events.">
22    <meta name="twitter:url" content="https://www.dyob.ca/stretch-yoga/">
23    <meta name="twitter:image" content="https://www.dyob.ca/content/images/size/w1200/2024/11/amcl-july-19-2023338_53069923140-1.jpg">
24    <meta name="twitter:label1" content="Written by">
25    <meta name="twitter:data1" content="Boyd Thomson">
26    <meta name="twitter:site" content="@ghost">
27    <meta property="og:image:width" content="1200">
28    <meta property="og:image:height" content="800">
29    
30    
30<script type="application/ld+json">
31{
32    "@context": "https://schema.org",
33    "@type": "Article",
34    "publisher": {
35        "@type": "Organization",
36        "name": "Boyd Thomson",
37        "url": "https://www.dyob.ca/",
38        "logo": {
39            "@type": "ImageObject",
40            "url": "https://www.dyob.ca/favicon.ico",
41            "width": 48,
42            "height": 48
43        }
44    },
45    "author": {
46        "@type": "Person",
47        "name": "Boyd Thomson",
48        "url": "https://www.dyob.ca/author/boyd/",
49        "sameAs": []
50    },
51    "headline": "Yoga",
52    "url": "https://www.dyob.ca/stretch-yoga/",
53    "datePublished": "2024-11-06T19:04:34.000Z",
54    "dateModified": "2026-05-25T00:21:52.000Z",
55    "image": {
56        "@type": "ImageObject",
57        "url": "https://www.dyob.ca/content/images/size/w1200/2024/11/amcl-july-19-2023338_53069923140-1.jpg",
58        "width": 1200,
59        "height": 800
60    },
61    "description": "Boyd is a founder of STRETCH, Vancouver's favourite Chinatown studio for yoga and events.\n\n\n\n\n",
62    "mainEntityOfPage": "https://www.dyob.ca/stretch-yoga/"
63}
64    </script>
64
65
66    <meta name="generator" content="Ghost 6.52">
67    <link rel="alternate" type="application/rss+xml" title="Boyd Thomson" href="https://www.dyob.ca/rss/">
68    
69    
69<script defer src="https://cdn.jsdelivr.net/ghost/sodo-search@~1.8/umd/sodo-search.min.js" data-key="fa028e542c9b0fe3a477fdc0ad" data-styles="https://cdn.jsdelivr.net/ghost/sodo-search@~1.8/umd/main.css" data-sodo-search="https://www.dyob.ca/" data-locale="en" crossorigin="anonymous"></script>
69
70    
71    <link href="https://www.dyob.ca/webmentions/receive/" rel="webmention">
72    
72<script defer src="/public/cards.min.js?v=f634b75eb6"></script>
72<style>:root {--ghost-accent-color: #e6d80e;}</style>
73    <link rel="stylesheet" type="text/css" href="/public/cards.min.css?v=f634b75eb6">
74    
74<script src="https://swetrix.org/swetrix.js" defer></script>
74
75    <link rel="stylesheet" href="/assets/css/screen.css?v=f634b75eb6">
76</head>
77<body class="page-template page-stretch-yoga">
78
79<nav class="mac-menubar" role="navigation" aria-label="Menu bar">
80
81  <div class="mac-menubar__item mac-menubar__apple" tabindex="0">
82    <img src="/assets/icons/tux.png?v=f634b75eb6" alt="Tux" width="14" height="14" style="image-rendering:pixelated;display:block;">
83    <div class="mac-menubar__dropdown">
84      <span class="disabled">About DYOB&hellip;</span>
85      <hr>
86      <a href="/">Home</a>
87      <a href="/about/">About Boyd</a>
88      <hr>
89      <span class="disabled">Restart&hellip;</span>
90    </div>
91  </div>
92
93  <div class="mac-menubar__item" tabindex="0">
94    File
95    <div class="mac-menubar__dropdown">
96      <a href="/tag/blog/">New Post&hellip;</a>
97      <hr>
98      <a href="/stretch-yoga/">Open STRETCH &amp; Yoga</a>
99      <a href="/tag/cycling/">Open Cycling</a>
100      <a href="/consulting/">Open Consulting</a>
101      <hr>
102      <a href="/resume/">Resume&hellip;</a>
103    </div>
104  </div>
105
106  <div class="mac-menubar__item" tabindex="0">
107    Edit
108    <div class="mac-menubar__dropdown">
109      <span class="disabled">Undo</span>
110      <hr>
111      <span class="disabled">Cut</span>
112      <span class="disabled">Copy</span>
113      <span class="disabled">Paste</span>
114      <hr>
115      <span class="disabled">Select All</span>
116    </div>
117  </div>
118
119  <div class="mac-menubar__item" tabindex="0">
120    View
121    <div class="mac-menubar__dropdown">
122      <a href="/">&#9632; By Icon</a>
123      <a href="/tag/blog/">By List&hellip;</a>
124      <hr>
125      <span class="disabled">Clean Up</span>
126    </div>
127  </div>
128
129  <div class="mac-menubar__item" tabindex="0">
130    Special
131    <div class="mac-menubar__dropdown">
132      <span class="disabled">Empty Trash&hellip;</span>
133      <hr>
134      <a href="/about/">Get Info</a>
135      <hr>
136      <span class="disabled">Restart</span>
137      <span class="disabled">Shut Down</span>
138    </div>
139  </div>
140
141  <div class="mac-menubar__clock" id="mac-clock">12:00 PM</div>
142
143</nav>
144
145<div class="mac-window">
146
147  <div class="mac-titlebar">
148    <div class="mac-titlebar__controls">
149      <div class="mac-titlebar__box"></div>
150      <div class="mac-titlebar__box"></div>
151      <div class="mac-titlebar__box"></div>
152    </div>
153    <div class="mac-titlebar__center">
154      <a href="https://www.dyob.ca">Boyd Thomson</a>
155    </div>
156    <div class="mac-titlebar__year" id="mac-year">2026</div>
157    <div class="mac-status mac-status--available" title="Available for contracts">
158      <span class="mac-status__dot"></span>
159      <span class="mac-status__label">AVAILABLE</span>
160    </div>
161  </div>
162
163  <div class="mac-body">
164    <main class="mac-main" id="main-content">
165      
166<article>
167  <div class="mac-page-header">
168    <h1>Yoga</h1>
169  </div>
170
171  <div class="mac-feature-image">
172    <img src="/content/images/2024/11/amcl-july-19-2023338_53069923140-1.jpg" alt="Yoga">
173  </div>
174
175  <div class="mac-page-body">
176    <p>Boyd is a founder of <a href="https://stretchvancouver.com/?ref=dyob.ca" rel="noreferrer">STRETCH</a>, Vancouver's favourite Chinatown studio for yoga and events.</p>
177<!--kg-card-begin: html-->
178<div id="ribbon-schedule"></div>
179<script
180  async
181  type="module"
182  host_id="4991"
183  teacher_ids="[1443]"
184  location_ids="[]"
185  tag_ids="[]"
186  hide_tags="true"
187  default_filter="show-all"
188  locale="en"
189  src="https://momence.com/plugin/host-schedule/host-schedule.js"
190></script>
190
191<!--kg-card-end: html-->
192
193  </div>
194</article>
195
196    </main>
197    <aside class="mac-sidebar">
198
199  <nav class="mac-sidebar-nav">
200    <ul>
201      <li class="">
202        <a href="/stretch-yoga/">STRETCH + YOGA</a>
203      </li>
204      <li class="">
205        <a href="/tag/cycling/">CYCLING</a>
206      </li>
207      <li class="">
208        <a href="/consulting/">CONSULTING</a>
209      </li>
210      <li>
211        <a href="https://words.my" target="_blank" rel="noopener">EAT MY WORDS</a>
212      </li>
213      <li class="">
214        <a href="/tag/blog/">BLOG</a>
215      </li>
216      <li class="">
217        <a href="/resume/">RESUME</a>
218      </li>
219      <li class="">
220        <a href="/about/">ABOUT</a>
221      </li>
222    </ul>
223  </nav>
224
225  <div class="mac-here">
226    <div class="mac-here__label">You are here:</div>
227    <div class="mac-here__badge">
228      
229      
230      
231      
232      PAGE
233      
234    </div>
235  </div>
236
237  <div class="mac-sidebar-icons">
238    <svg viewBox="0 0 48 48" xmlns="http://www.w3.org/2000/svg">
239  <!-- disk body (clipped top-right corner) -->
240  <polygon points="4,2 36,2 44,10 44,46 4,46" fill="currentColor"/>
241  <!-- label window (white) -->
242  <rect x="8" y="4"  width="24" height="16" fill="white"/>
243  <!-- lines on label -->
244  <rect x="11" y="8"  width="18" height="2"  fill="currentColor"/>
245  <rect x="11" y="12" width="18" height="2"  fill="currentColor"/>
246  <rect x="11" y="16" width="12" height="2"  fill="currentColor"/>
247  <!-- write-protect notch (white square top-right) -->
248  <rect x="36" y="2"  width="8"  height="8"  fill="white"/>
249  <!-- shutter plate (white) -->
250  <rect x="9"  y="30" width="30" height="12" fill="white"/>
251  <!-- shutter slot (dark opening) -->
252  <rect x="15" y="30" width="14" height="12" fill="currentColor"/>
253</svg>
254    <svg viewBox="0 0 48 48" xmlns="http://www.w3.org/2000/svg">
255  <!-- disk body (clipped top-right corner) -->
256  <polygon points="4,2 36,2 44,10 44,46 4,46" fill="currentColor"/>
257  <!-- label window (white) -->
258  <rect x="8" y="4"  width="24" height="16" fill="white"/>
259  <!-- lines on label -->
260  <rect x="11" y="8"  width="18" height="2"  fill="currentColor"/>
261  <rect x="11" y="12" width="18" height="2"  fill="currentColor"/>
262  <rect x="11" y="16" width="12" height="2"  fill="currentColor"/>
263  <!-- write-protect notch (white square top-right) -->
264  <rect x="36" y="2"  width="8"  height="8"  fill="white"/>
265  <!-- shutter plate (white) -->
266  <rect x="9"  y="30" width="30" height="12" fill="white"/>
267  <!-- shutter slot (dark opening) -->
268  <rect x="15" y="30" width="14" height="12" fill="currentColor"/>
269</svg>
270  </div>
271
272  <div class="mac-sidebar-btns">
273    <button type="button" class="mac-btn" id="help-btn">HELP</button>
274    <a href="/tag/blog/" class="mac-btn">SEARCH</a>
275    <a href="/" class="mac-btn">MENU</a>
276  </div>
277
278</aside>
279  </div>
280
281  <footer class="mac-dock">
282  <a class="mac-dock-item" href="https://www.dyob.ca" title="Home"><img src="/assets/icons/globe.png?v=f634b75eb6" alt="Globe" class="mac-icon-img">
283</a>
284  <a class="mac-dock-item" href="/stretch-yoga/" title="STRETCH &amp; Yoga"><img src="/assets/icons/yoga.png?v=f634b75eb6" alt="Yoga" class="mac-icon-img">
285</a>
286  <a class="mac-dock-item" href="/tag/cycling/" title="Cycling"><img src="/assets/icons/cycling.png?v=f634b75eb6" alt="Cycling" class="mac-icon-img">
287</a>
288  <a class="mac-dock-item" href="/consulting/" title="Consulting"><img src="/assets/icons/monitor.png?v=f634b75eb6" alt="Monitor" class="mac-icon-img">
289</a>
290  <a class="mac-dock-item" href="/tag/blog/" title="Blog"><img src="/assets/icons/document.png?v=f634b75eb6" alt="Document" class="mac-icon-img">
291</a>
292  <a class="mac-dock-item" href="/resume/" title="Resume"><svg viewBox="0 0 48 48" xmlns="http://www.w3.org/2000/svg">
293  <!-- disk body (clipped top-right corner) -->
294  <polygon points="4,2 36,2 44,10 44,46 4,46" fill="currentColor"/>
295  <!-- label window (white) -->
296  <rect x="8" y="4"  width="24" height="16" fill="white"/>
297  <!-- lines on label -->
298  <rect x="11" y="8"  width="18" height="2"  fill="currentColor"/>
299  <rect x="11" y="12" width="18" height="2"  fill="currentColor"/>
300  <rect x="11" y="16" width="12" height="2"  fill="currentColor"/>
301  <!-- write-protect notch (white square top-right) -->
302  <rect x="36" y="2"  width="8"  height="8"  fill="white"/>
303  <!-- shutter plate (white) -->
304  <rect x="9"  y="30" width="30" height="12" fill="white"/>
305  <!-- shutter slot (dark opening) -->
306  <rect x="15" y="30" width="14" height="12" fill="currentColor"/>
307</svg>
308</a>
309  <a class="mac-dock-item" href="/about/" title="About"><img src="/assets/icons/envelope.png?v=f634b75eb6" alt="Envelope" class="mac-icon-img">
310</a>
311</footer>
312
313  <div class="mac-growbox">
314    <div class="mac-growbox__handle"></div>
315  </div>
316
317</div>
318
319<script>
320  // Dynamic year
321  document.getElementById('mac-year').textContent = new Date().getFullYear();
322
323  // Menu bar clock
324  function updateClock() {
325    var now = new Date();
326    var h = now.getHours(), m = now.getMinutes();
327    var ampm = h >= 12 ? 'PM' : 'AM';
328    h = h % 12 || 12;
329    document.getElementById('mac-clock').textContent =
330      h + ':' + (m < 10 ? '0' : '') + m + ' ' + ampm;
331  }
332  updateClock();
333  setInterval(updateClock, 10000);
334
335  // Close dropdowns when clicking outside
336  document.addEventListener('click', function(e) {
337    if (!e.target.closest('.mac-menubar__item')) {
338      document.querySelectorAll('.mac-menubar__item').forEach(function(el) {
339        el.blur();
340      });
341    }
342  });
343</script>
343
344
345<script src="https://swetrix.org/swetrix.js" defer></script>
vendor: 1 bytes, line 345
345
346<script>
347  document.addEventListener("DOMContentLoaded", function () {
348    swetrix.init("LH1kVkeTMEr7", {
349      apiURL: "https://apiswetrix.words.my/log"
350    });
351    swetrix.trackViews();
352  });
353</script>
353
354<noscript>
355  <img src="https://apiswetrix.words.my/log/noscript?pid=LH1kVkeTMEr7" alt="" referrerpolicy="no-referrer-when-downgrade">
356</noscript>
357
358<div id="help-overlay" class="help-overlay" hidden>
359  <div class="help-window" role="dialog" aria-modal="true" aria-labelledby="help-titlebar-label">
360
361    <div class="help-titlebar">
362      <div class="help-titlebar__controls">
363        <div class="help-titlebar__closebox" id="help-close-btn"
364             role="button" tabindex="0" aria-label="Close help"></div>
365      </div>
366      <div class="help-titlebar__title">
367        <span id="help-titlebar-label">HELP DESK</span>
368      </div>
369    </div>
370
371    <div class="help-terminal" id="help-terminal" aria-live="polite" aria-atomic="false"></div>
372
373    <div class="help-inputrow">
374      <span class="help-inputrow__prompt">&gt;</span>
375      <input type="text" id="help-input" class="help-inputrow__input"
376             placeholder="TYPE YOUR QUESTION..." autocomplete="off"
377             spellcheck="false" maxlength="512" disabled>
378      <button type="button" id="help-send-btn" class="help-inputrow__send" disabled>SEND</button>
379    </div>
380
381  </div>
382</div>
383
384<script>
385;(function () {
386  'use strict';
387
388  var MX        = 'https://matrix.dyob.ca';
389  var ROOM      = '!QTGmhaYUJdNoTgkWxm:matrix.dyob.ca';
390  var ROOM_ENC  = '!QTGmhaYUJdNoTgkWxm%3Amatrix.dyob.ca';
391  var WEB_USER  = '@webuser:matrix.dyob.ca';
392  var WEB_PASS  = '2C0nXehnlgu5zdVZCf6vuz';
393
394  var token       = null;
395  var nextBatch   = null;
396  var syncActive  = false;
397  var waitingReply = false;
398  var txnCounter  = Date.now();
399
400  // Root event of this browser session's Matrix thread. Every message after
401  // the first is sent as an m.thread child of this root, which is what gives
402  // the help desk agent a single continuous session instead of a new
403  // (empty-history) one per message. Kept in sessionStorage so it survives
404  // page navigation within the tab, but not a new tab or a browser restart.
405  var THREAD_KEY  = 'dyobHelpThreadRoot';
406  var threadRoot  = null;
407  try { threadRoot = window.sessionStorage.getItem(THREAD_KEY); } catch (e) {}
408
409  function setThreadRoot(id) {
410    threadRoot = id;
411    try { window.sessionStorage.setItem(THREAD_KEY, id); } catch (e) {}
412  }
413
414  // The thread root a received event belongs to, or null if it is unthreaded.
415  function eventThreadRoot(ev) {
416    var rel = ev && ev.content && ev.content['m.relates_to'];
417    if (rel && rel.rel_type === 'm.thread') return rel.event_id;
418    return null;
419  }
420
421  // ── helpers ──────────────────────────────────────────────────────
422
423  function $(id) { return document.getElementById(id); }
424
425  // Bot replies sometimes arrive with markdown; the terminal shows raw
426  // text, so flatten the common constructs to plain text.
427  function stripMd(s) {
428    return s
429      .replace(/^#{1,6}\s+/gm, '')
430      .replace(/\*\*([^*]+)\*\*/g, '$1')
431      .replace(/\*([^*\n]+)\*/g, '$1')
432      .replace(/__([^_]+)__/g, '$1')
433      .replace(/`([^`]+)`/g, '$1')
434      .replace(/\[([^\]]+)\]\(([^)]+)\)/g, '$1 ($2)');
435  }
436
437  function appendMsg(type, text) {
438    var el = $('help-terminal');
439    if (!el) return;
440    // Remove blinking cursor element if present
441    var cur = el.querySelector('.help-cursor');
442    if (cur) cur.remove();
443
444    var div = document.createElement('div');
445    div.className = 'help-msg help-msg--' + type;
446    div.textContent = text;
447    el.appendChild(div);
448
449    // Re-add cursor after last line (only when idle)
450    if (type !== 'waiting') {
451      var curEl = document.createElement('span');
452      curEl.className = 'help-cursor';
453      el.appendChild(curEl);
454    }
455    el.scrollTop = el.scrollHeight;
456  }
457
458  function removeWaiting() {
459    var el = $('help-terminal');
460    if (!el) return;
461    var w = el.querySelector('.help-msg--waiting');
462    if (w) w.remove();
463  }
464
465  function setInputEnabled(on) {
466    var inp  = $('help-input');
467    var btn  = $('help-send-btn');
468    if (inp) inp.disabled  = !on;
469    if (btn) btn.disabled  = !on;
470    if (on && inp) inp.focus();
471  }
472
473  // ── Matrix API ───────────────────────────────────────────────────
474
475  function mxFetch(path, opts) {
476    var headers = { 'Content-Type': 'application/json' };
477    if (token) headers['Authorization'] = 'Bearer ' + token;
478    return fetch(MX + '/_matrix/client/v3' + path, {
479      method: opts && opts.method ? opts.method : 'GET',
480      headers: headers,
481      body: opts && opts.body ? JSON.stringify(opts.body) : undefined
482    }).then(function (r) { return r.json(); });
483  }
484
485  function mxLogin() {
486    return mxFetch('/login', {
487      method: 'POST',
488      body: {
489        type: 'm.login.password',
490        identifier: { type: 'm.id.user', user: 'webuser' },
491        password: WEB_PASS,
492        device_id: 'DYOB_HELP_CHAT',
493        initial_device_display_name: 'dyob.ca help chat'
494      }
495    }).then(function (d) {
496      if (!d.access_token) throw new Error(d.error || 'LOGIN FAILED');
497      token = d.access_token;
498    });
499  }
500
501  var SYNC_FILTER = encodeURIComponent(JSON.stringify({
502    room: {
503      rooms: [ROOM],
504      timeline: { limit: 50, types: ['m.room.message'] }
505    },
506    presence:     { not_types: ['*'] },
507    account_data: { not_types: ['*'] }
508  }));
509
510  function mxInitSync() {
511    // Pull a next_batch that represents NOW — skip all history
512    var initFilter = encodeURIComponent(JSON.stringify({
513      room: {
514        rooms: [ROOM],
515        timeline: { limit: 0 }
516      },
517      presence:     { not_types: ['*'] },
518      account_data: { not_types: ['*'] }
519    }));
520    return mxFetch('/sync?filter=' + initFilter + '&timeout=0')
521      .then(function (d) { nextBatch = d.next_batch; });
522  }
523
524  function pollLoop() {
525    if (!syncActive) return;
526    mxFetch('/sync?since=' + encodeURIComponent(nextBatch) +
527            '&timeout=10000&filter=' + SYNC_FILTER)
528      .then(function (data) {
529        if (!syncActive) return;
530        nextBatch = data.next_batch;
531        var room = data.rooms && data.rooms.join && data.rooms.join[ROOM];
532        if (room && room.timeline && room.timeline.events) {
533          room.timeline.events.forEach(function (ev) {
534            if (ev.type === 'm.room.message' &&
535                ev.sender !== WEB_USER &&
536                (!threadRoot || eventThreadRoot(ev) === threadRoot) &&
537                ev.content && ev.content.msgtype === 'm.text') {
538              removeWaiting();
539              appendMsg('bot', stripMd(ev.content.body));
540              waitingReply = false;
541              setInputEnabled(true);
542            }
543          });
544        }
545        if (syncActive) pollLoop();
546      })
547      .catch(function () {
548        if (syncActive) setTimeout(pollLoop, 3000);
549      });
550  }
551
552  // ── send ─────────────────────────────────────────────────────────
553
554  function sendMessage() {
555    var inp  = $('help-input');
556    var text = inp ? inp.value.trim() : '';
557    if (!text || waitingReply || !syncActive) return;
558
559    inp.value   = '';
560    waitingReply = true;
561    setInputEnabled(false);
562    appendMsg('user', '> ' + text);
563    appendMsg('waiting', 'HERMES IS THINKING...');
564
565    var tid  = 'm' + (txnCounter++);
566    var body = { msgtype: 'm.text', body: text };
567    if (threadRoot) {
568      body['m.relates_to'] = {
569        rel_type: 'm.thread',
570        event_id: threadRoot,
571        is_falling_back: true,
572        'm.in_reply_to': { event_id: threadRoot }
573      };
574    }
575    mxFetch('/rooms/' + ROOM_ENC + '/send/m.room.message/' + tid, {
576      method: 'PUT',
577      body: body
578    }).then(function (d) {
579      // The first message of a session is the thread root itself.
580      if (!threadRoot && d && d.event_id) setThreadRoot(d.event_id);
581      if (d && !d.event_id) throw new Error(d.error || 'SEND FAILED');
582    }).catch(function () {
583      removeWaiting();
584      appendMsg('error', '[ERROR] MESSAGE NOT SENT — PLEASE TRY AGAIN');
585      waitingReply = false;
586      setInputEnabled(true);
587    });
588  }
589
590  // ── open / close ─────────────────────────────────────────────────
591
592  function openModal() {
593    var overlay = $('help-overlay');
594    var terminal = $('help-terminal');
595    if (!overlay) return;
596    // Reset
597    if (terminal) terminal.innerHTML = '';
598    syncActive   = false;
599    waitingReply = false;
600    token        = null;
601    nextBatch    = null;
602
603    overlay.hidden = false;
604    setInputEnabled(false);
605    syncActive = true;
606
607    appendMsg('system', 'DYOB.CA HELP SYSTEM v1.0');
608    appendMsg('system', 'CONNECTING...');
609
610    mxLogin()
611      .then(function () {
612        appendMsg('system', 'AUTH OK — HERMES AGENT ONLINE');
613        appendMsg('system', '─────────────────────────────────────────');
614        appendMsg('system', 'ASK ANYTHING ABOUT THIS SITE OR BOYD\'S WORK.');
615        return mxInitSync();
616      })
617      .then(function () {
618        setInputEnabled(true);
619        pollLoop();
620      })
621      .catch(function (e) {
622        appendMsg('error', 'CONNECTION ERROR: ' + (e && e.message ? e.message : String(e)));
623      });
624  }
625
626  function closeModal() {
627    syncActive  = false;
628    token       = null;
629    nextBatch   = null;
630    waitingReply = false;
631    var overlay = $('help-overlay');
632    if (overlay) overlay.hidden = true;
633  }
634
635  // ── wire up ──────────────────────────────────────────────────────
636
637  document.addEventListener('DOMContentLoaded', function () {
638    var helpBtn  = $('help-btn');
639    var closeBtn = $('help-close-btn');
640    var overlay  = $('help-overlay');
641    var inp      = $('help-input');
642    var sendBtn  = $('help-send-btn');
643
644    if (helpBtn)  helpBtn.addEventListener('click', openModal);
645    if (closeBtn) {
646      closeBtn.addEventListener('click', closeModal);
647      closeBtn.addEventListener('keydown', function (e) {
648        if (e.key === 'Enter' || e.key === ' ') closeModal();
649      });
650    }
651    if (overlay) {
652      overlay.addEventListener('click', function (e) {
653        if (e.target === overlay) closeModal();
654      });
655    }
656    if (inp) {
657      inp.addEventListener('keydown', function (e) {
658        if (e.key === 'Enter') sendMessage();
659      });
660    }
661    if (sendBtn) sendBtn.addEventListener('click', sendMessage);
662
663    document.addEventListener('keydown', function (e) {
664      var ov = $('help-overlay');
665      if (e.key === 'Escape' && ov && !ov.hidden) closeModal();
666    });
667  });
668
669  window.openHelpModal = openModal;
670}());
671</script>
671
672
673<script>
674  document.addEventListener("DOMContentLoaded", function () {
675    swetrix.init("LH1kVkeTMEr7");
676    swetrix.trackViews();
677  });
678</script>
678
679
680<noscript>
681  <img
682    src="https://apiswetrix.words.my/log/noscript?pid=LH1kVkeTMEr7"
683    alt=""
684    referrerpolicy="no-referrer-when-downgrade"
685  />
686</noscript>
687<script type="module" src="https://static.cloudflareinsights.com/beacon.min.js/v31edd6df95cf4e85bb4c19e7a9bdbcba1788362987495" integrity="sha512-iIg7k2xntmwu6/uSb5tpc/hySgZc4eoL31yB29W6tJFo2akwjPWcEqnCEdJvGexCL0KEQwVYv5BlowfhVz26hg==" data-cf-beacon='{"version":"2024.11.0","token":"e422459f151f4e18b9a4ad973369e740","r":1,"spa":2}' crossorigin="anonymous"></script>
687
688</body>
689</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.