PageSourceSearch

https://the-gadgeteer.com/2026/09/24/5-things-to-love-about-the-new-googlebook-os/

html the-gadgeteer.com collected 2026-09-24 17:34:47 UTC 201,990 bytes, 3,420 lines download raw bytes

1<!DOCTYPE html>
2<html lang="en-US" prefix="og: https://ogp.me/ns#">
3<head>
4<meta charset="UTF-8">
5<meta name="viewport" content="width=device-width, initial-scale=1">
6
7<!-- Search Engine Optimization by Rank Math PRO - https://rankmath.com/ -->
8<title>5 Reasons Googlebook OS Could Be Google’s Most Interesting Laptop Move Yet</title>
9<meta name="description" content="Googlebook OS"/>
10<meta name="robots" content="follow, index, max-snippet:-1, max-video-preview:-1, max-image-preview:large"/>
11<link rel="canonical" href="https://the-gadgeteer.com/2026/09/24/5-things-to-love-about-the-new-googlebook-os/" />
12<meta property="og:locale" content="en_US" />
13<meta property="og:type" content="article" />
14<meta property="og:title" content="5 Reasons Googlebook OS Could Be Google’s Most Interesting Laptop Move Yet" />
15<meta property="og:description" content="Googlebook OS" />
16<meta property="og:url" content="https://the-gadgeteer.com/2026/09/24/5-things-to-love-about-the-new-googlebook-os/" />
17<meta property="og:site_name" content="The Gadgeteer" />
18<meta property="article:publisher" content="https://www.facebook.com/gadgeteer" />
19<meta property="article:author" content="https://www.facebook.com/julie.strietelmeier/" />
20<meta property="article:tag" content="chromebook" />
21<meta property="article:tag" content="computer" />
22<meta property="article:tag" content="Google" />
23<meta property="article:tag" content="Laptop" />
24<meta property="article:section" content="Articles" />
25<meta property="og:updated_time" content="2026-09-24T06:17:27-05:00" />
26<meta property="og:image" content="https://the-gadgeteer.com/wp-content/uploads/2026/09/GoogleBook-OS-Cover.jpeg" />
27<meta property="og:image:secure_url" content="https://the-gadgeteer.com/wp-content/uploads/2026/09/GoogleBook-OS-Cover.jpeg" />
28<meta property="og:image:width" content="1440" />
29<meta property="og:image:height" content="1080" />
30<meta property="og:image:alt" content="GoogleBook OS" />
31<meta property="og:image:type" content="image/jpeg" />
32<meta property="article:published_time" content="2026-09-24T05:30:49-05:00" />
33<meta property="article:modified_time" content="2026-09-24T06:17:27-05:00" />
34<meta name="twitter:card" content="summary_large_image" />
35<meta name="twitter:title" content="5 Reasons Googlebook OS Could Be Google’s Most Interesting Laptop Move Yet" />
36<meta name="twitter:description" content="Googlebook OS" />
37<meta name="twitter:site" content="@thegadgeteer" />
38<meta name="twitter:creator" content="@thegadgeteer" />
39<meta name="twitter:image" content="https://the-gadgeteer.com/wp-content/uploads/2026/09/GoogleBook-OS-Cover.jpeg" />
40<meta name="twitter:label1" content="Written by" />
41<meta name="twitter:data1" content="Rei Padla" />
42<meta name="twitter:label2" content="Time to read" />
43<meta name="twitter:data2" content="6 minutes" />
44<script type="application/ld+json" class="rank-math-schema-pro">{"@context":"https://schema.org","@graph":[{"@type":"Organization","@id":"https://the-gadgeteer.com/#organization","name":"The Gadgeteer","sameAs":["https://www.facebook.com/gadgeteer","https://twitter.com/thegadgeteer"],"logo":{"@type":"ImageObject","@id":"https://the-gadgeteer.com/#logo","url":"https://the-gadgeteer.com/wp-content/uploads/2013/12/gadgeteer_logo_2013.png","contentUrl":"https://the-gadgeteer.com/wp-content/uploads/2013/12/gadgeteer_logo_2013.png","caption":"The Gadgeteer","inLanguage":"en-US","width":"300","height":"92"}},{"@type":"WebSite","@id":"https://the-gadgeteer.com/#website","url":"https://the-gadgeteer.com","name":"The Gadgeteer","publisher":{"@id":"https://the-gadgeteer.com/#organization"},"inLanguage":"en-US"},{"@type":"ImageObject","@id":"https://the-gadgeteer.com/wp-content/uploads/2026/09/GoogleBook-OS-Cover.jpeg","url":"https://the-gadgeteer.com/wp-content/uploads/2026/09/GoogleBook-OS-Cover.jpeg","width":"1440","height":"1080","caption":"GoogleBook OS","inLanguage":"en-US"},{"@type":"WebPage","@id":"https://the-gadgeteer.com/2026/09/24/5-things-to-love-about-the-new-googlebook-os/#webpage","url":"https://the-gadgeteer.com/2026/09/24/5-things-to-love-about-the-new-googlebook-os/","name":"5 Reasons Googlebook OS Could Be Google\u2019s Most Interesting Laptop Move Yet","datePublished":"2026-09-24T05:30:49-05:00","dateModified":"2026-09-24T06:17:27-05:00","isPartOf":{"@id":"https://the-gadgeteer.com/#website"},"primaryImageOfPage":{"@id":"https://the-gadgeteer.com/wp-content/uploads/2026/09/GoogleBook-OS-Cover.jpeg"},"inLanguage":"en-US"},{"@type":"Person","@id":"https://the-gadgeteer.com/author/rei/","name":"Rei Padla","url":"https://the-gadgeteer.com/author/rei/","image":{"@type":"ImageObject","@id":"https://secure.gravatar.com/avatar/ace25749c026e0e13e41c8d427699211a5edc7e78139caea021bbc11de81cc20?s=96&amp;d=robohash&amp;r=g","url":"https://secure.gravatar.com/avatar/ace25749c026e0e13e41c8d427699211a5edc7e78139caea021bbc11de81cc20?s=96&amp;d=robohash&amp;r=g","caption":"Rei Padla","inLanguage":"en-US"},"sameAs":["http://the-gadgeteer.com"],"worksFor":{"@id":"https://the-gadgeteer.com/#organization"}},{"@type":"BlogPosting","headline":"5 Reasons Googlebook OS Could Be Google\u2019s Most Interesting Laptop Move Yet","keywords":"Googlebook OS","datePublished":"2026-09-24T05:30:49-05:00","dateModified":"2026-09-24T06:17:27-05:00","articleSection":"Articles","author":{"@id":"https://the-gadgeteer.com/author/rei/","name":"Rei Padla"},"publisher":{"@id":"https://the-gadgeteer.com/#organization"},"description":"Googlebook OS","name":"5 Reasons Googlebook OS Could Be Google\u2019s Most Interesting Laptop Move Yet","@id":"https://the-gadgeteer.com/2026/09/24/5-things-to-love-about-the-new-googlebook-os/#richSnippet","isPartOf":{"@id":"https://the-gadgeteer.com/2026/09/24/5-things-to-love-about-the-new-googlebook-os/#webpage"},"image":{"@id":"https://the-gadgeteer.com/wp-content/uploads/2026/09/GoogleBook-OS-Cover.jpeg"},"inLanguage":"en-US","mainEntityOfPage":{"@id":"https://the-gadgeteer.com/2026/09/24/5-things-to-love-about-the-new-googlebook-os/#webpage"}}]}</script>
44
45<!-- /Rank Math WordPress SEO plugin -->
46
47<link rel='dns-prefetch' href='//hcaptcha.com' />
48<link rel="alternate" type="application/rss+xml" title="The Gadgeteer &raquo; Feed" href="https://the-gadgeteer.com/feed/" />
49<link rel="alternate" type="application/rss+xml" title="The Gadgeteer &raquo; Comments Feed" href="https://the-gadgeteer.com/comments/feed/" />
50<link rel="preload" href="https://the-gadgeteer.com/wp-content/themes/gadgeteer/assets/fonts/space-grotesk-300-700-latin.woff2" as="font" type="font/woff2" crossorigin>
51<link rel="preload" href="https://the-gadgeteer.com/wp-content/themes/gadgeteer/assets/fonts/jetbrains-mono-100-800-latin.woff2" as="font" type="font/woff2" crossorigin>
52<link rel="preload" href="https://the-gadgeteer.com/wp-content/themes/gadgeteer/assets/fonts/instrument-serif-400-latin.woff2" as="font" type="font/woff2" crossorigin>
53<link rel="alternate" type="application/rss+xml" title="The Gadgeteer &raquo; 5 Reasons Googlebook OS Could Be Google’s Most Interesting Laptop Move Yet Comments Feed" href="https://the-gadgeteer.com/2026/09/24/5-things-to-love-about-the-new-googlebook-os/feed/" />
54<link rel="alternate" title="oEmbed (JSON)" type="application/json+oembed" href="https://the-gadgeteer.com/wp-json/oembed/1.0/embed?url=https%3A%2F%2Fthe-gadgeteer.com%2F2026%2F09%2F24%2F5-things-to-love-about-the-new-googlebook-os%2F" />
55<link rel="alternate" title="oEmbed (XML)" type="text/xml+oembed" href="https://the-gadgeteer.com/wp-json/oembed/1.0/embed?url=https%3A%2F%2Fthe-gadgeteer.com%2F2026%2F09%2F24%2F5-things-to-love-about-the-new-googlebook-os%2F&#038;format=xml" />
56<style id="wp-img-auto-sizes-contain-inline-css">
57img:is([sizes=auto i],[sizes^="auto," i]){contain-intrinsic-size:3000px 1500px}
58/*# sourceURL=wp-img-auto-sizes-contain-inline-css */
59</style>
60<link rel='stylesheet' id='reviewcard-system-style-css' href='https://the-gadgeteer.com/wp-content/plugins/ewdi-review-system/css/reviewcard-system.css?ver=1.0' media='all' />
61
62<style id="global-styles-inline-css">
63:root{--wp--preset--aspect-ratio--square: 1;--wp--preset--aspect-ratio--4-3: 4/3;--wp--preset--aspect-ratio--3-4: 3/4;--wp--preset--aspect-ratio--3-2: 3/2;--wp--preset--aspect-ratio--2-3: 2/3;--wp--preset--aspect-ratio--16-9: 16/9;--wp--preset--aspect-ratio--9-16: 9/16;--wp--preset--color--black: #000000;--wp--preset--color--cyan-bluish-gray: #abb8c3;--wp--preset--color--white: #ffffff;--wp--preset--color--pale-pink: #f78da7;--wp--preset--color--vivid-red: #cf2e2e;--wp--preset--color--luminous-vivid-orange: #ff6900;--wp--preset--color--luminous-vivid-amber: #fcb900;--wp--preset--color--light-green-cyan: #7bdcb5;--wp--preset--color--vivid-green-cyan: #00d084;--wp--preset--color--pale-cyan-blue: #8ed1fc;--wp--preset--color--vivid-cyan-blue: #0693e3;--wp--preset--color--vivid-purple: #9b51e0;--wp--preset--gradient--vivid-cyan-blue-to-vivid-purple: linear-gradient(135deg,rgb(6,147,227) 0%,rgb(155,81,224) 100%);--wp--preset--gradient--light-green-cyan-to-vivid-green-cyan: linear-gradient(135deg,rgb(122,220,180) 0%,rgb(0,208,130) 100%);--wp--preset--gradient--luminous-vivid-amber-to-luminous-vivid-orange: linear-gradient(135deg,rgb(252,185,0) 0%,rgb(255,105,0) 100%);--wp--preset--gradient--luminous-vivid-orange-to-vivid-red: linear-gradient(135deg,rgb(255,105,0) 0%,rgb(207,46,46) 100%);--wp--preset--gradient--very-light-gray-to-cyan-bluish-gray: linear-gradient(135deg,rgb(238,238,238) 0%,rgb(169,184,195) 100%);
63--wp--preset--gradient--cool-to-warm-spectrum: linear-gradient(135deg,rgb(74,234,220) 0%,rgb(151,120,209) 20%,rgb(207,42,186) 40%,rgb(238,44,130) 60%,rgb(251,105,98) 80%,rgb(254,248,76) 100%);--wp--preset--gradient--blush-light-purple: linear-gradient(135deg,rgb(255,206,236) 0%,rgb(152,150,240) 100%);--wp--preset--gradient--blush-bordeaux: linear-gradient(135deg,rgb(254,205,165) 0%,rgb(254,45,45) 50%,rgb(107,0,62) 100%);--wp--preset--gradient--luminous-dusk: linear-gradient(135deg,rgb(255,203,112) 0%,rgb(199,81,192) 50%,rgb(65,88,208) 100%);--wp--preset--gradient--pale-ocean: linear-gradient(135deg,rgb(255,245,203) 0%,rgb(182,227,212) 50%,rgb(51,167,181) 100%);--wp--preset--gradient--electric-grass: linear-gradient(135deg,rgb(202,248,128) 0%,rgb(113,206,126) 100%);--wp--preset--gradient--midnight: linear-gradient(135deg,rgb(2,3,129) 0%,rgb(40,116,252) 100%);--wp--preset--font-size--small: 13px;--wp--preset--font-size--medium: 20px;--wp--preset--font-size--large: 36px;--wp--preset--font-size--x-large: 42px;--wp--preset--spacing--20: 0.44rem;--wp--preset--spacing--30: 0.67rem;--wp--preset--spacing--40: 1rem;--wp--preset--spacing--50: 1.5rem;--wp--preset--spacing--60: 2.25rem;--wp--preset--spacing--70: 3.38rem;--wp--preset--spacing--80: 5.06rem;--wp--preset--shadow--natural: 6px 6px 9px rgba(0, 0, 0, 0.2);--wp--preset--shadow--deep: 12px 12px 50px rgba(0, 0, 0, 0.4);--wp--preset--shadow--sharp: 6px 6px 0px rgba(0, 0, 0, 0.2);--wp--preset--shadow--outlined: 6px 6px 0px -3px rgb(255, 255, 255), 6px 6px rgb(0, 0, 0);--wp--preset--shadow--crisp: 6px 6px 0px rgb(0, 0, 0);}.wp-block-button{--wp--preset--dimension--25: 25%;--wp--preset--dimension--50: 50%;--wp--preset--dimension--75: 75%;--wp--preset--dimension--100: 100%;}:where(body) { margin: 0; }:where(.is-layout-flex){gap: 0.5em;}:where(.is-layout-grid){gap: 0.5em;}body .is-layout-flex{display: flex;}.is-layout-flex{flex-wrap: wrap;align-items: center;}.is-layout-flex > :is(*, div){margin: 0;}body .is-layout-grid{display: grid;}.is-layout-grid > :is(*, div){margin: 0;}body{padding-top: 0px;padding-right: 0px;padding-bottom: 0px;padding-left: 0px;}:root :where(.wp-element-button, .wp-block-button__link){background-color: #32373c;border-width: 0;color: #fff;font-family: inherit;font-size: inherit;font-style: inherit;font-weight: inherit;letter-spacing: inherit;line-height: inherit;padding-top: calc(0.667em + 2px);padding-right: calc(1.333em + 2px);padding-bottom: calc(0.667em + 2px);padding-left: calc(1.333em + 2px);text-decoration: none;text-transform: inherit;}.has-black-color{color: var(--wp--preset--color--black) !important;}.has-cyan-bluish-gray-color{color: var(--wp--preset--color--cyan-bluish-gray) !important;}.has-white-color{color: var(--wp--preset--color--white) !important;}.has-pale-pink-color{color: var(--wp--preset--color--pale-pink) !important;}.has-vivid-red-color{color: var(--wp--preset--color--vivid-red) !important;}.has-luminous-vivid-orange-color{color: var(--wp--preset--color--luminous-vivid-orange) !important;}.has-luminous-vivid-amber-color{color: var(--wp--preset--color--luminous-vivid-amber) !important;}.has-light-green-cyan-color{color: var(--wp--preset--color--light-green-cyan) !important;}.has-vivid-green-cyan-color{color: var(--wp--preset--color--vivid-green-cyan) !important;}.has-pale-cyan-blue-color{color: var(--wp--preset--color--pale-cyan-blue) !important;}.has-vivid-cyan-blue-color{color: var(--wp--preset--color--vivid-cyan-blue) !important;}.has-vivid-purple-color{color: var(--wp--preset--color--vivid-purple) !important;}.has-black-background-color{background-color: var(--wp--preset--color--black) !important;}.has-cyan-bluish-gray-background-color{background-color: var(--wp--preset--color--cyan-bluish-gray) !important;}.has-white-background-color{background-color: var(--wp--preset--color--white) !important;}.has-pale-pink-background-color{background-color: var(--wp--preset--color--pale-pink) !important;}.has-vivid-red-background-color{background-color: var(--wp--preset--color--vivid-red) !important;}.has-luminous-vivid-orange-background-color{background-color: var(--wp--preset--color--luminous-vivid-orange) !important;}.has-luminous-vivid-amber-background-color{background-color: var(--wp--preset--color--luminous-vivid-amber) !important;}.has-light-green-cyan-background-color{background-color: var(--wp--preset--color--light-green-cyan) !important;}.has-vivid-green-cyan-background-color{background-color: var(--wp--preset--color--vivid-green-cyan) !important;}.has-pale-cyan-blue-background-color{background-color: var(--wp--preset--color--pale-cyan-blue) !important;}.has-vivid-cyan-blue-background-color{background-color: var(--wp--preset--color--vivid-cyan-blue) !important;}.has-vivid-purple-background-color{background-color: var(--wp--preset--color--vivid-purple) !important;}.has-black-border-color{border-color: var(--wp--preset--color--black) !important;}.has-cyan-bluish-gray-border-color{border-color: var(--wp--preset--color--cyan-bluish-gray) !important;}.has-white-border-color{border-color: var(--wp--preset--color--white) !important;}.has-pale-pink-border-color{border-color: var(--wp--preset--color--pale-pink) !important;}.has-vivid-red-border-color{border-color: var(--wp--preset--color--vivid-red) !important;}.has-luminous-vivid-orange-border-color{border-color: var(--wp--preset--color--luminous-vivid-orange) !important;}.has-luminous-vivid-amber-border-color{border-color: var(--wp--preset--color--luminous-vivid-amber) !important;}.has-light-green-cyan-border-color{border-color: var(--wp--preset--color--light-green-cyan) !important;}.has-vivid-green-cyan-border-color{border-color: var(--wp--preset--color--vivid-green-cyan) !important;}.has-pale-cyan-blue-border-color{border-color: var(--wp--preset--color--pale-cyan-blue) !important;}.has-vivid-cyan-blue-border-color{border-color: var(--wp--preset--color--vivid-cyan-blue) !important;}.has-vivid-purple-border-color{border-color: var(--wp--preset--color--vivid-purple) !important;}.has-vivid-cyan-blue-to-vivid-purple-gradient-background{background: var(--wp--preset--gradient--vivid-cyan-blue-to-vivid-purple) !important;}.has-light-green-cyan-to-vivid-green-cyan-gradient-background{background: var(--wp--preset--gradient--light-green-cyan-to-vivid-green-cyan) !important;}.has-luminous-vivid-amber-to-luminous-vivid-orange-gradient-background{background: var(--wp--preset--gradient--luminous-vivid-amber-to-luminous-vivid-orange) !important;}.has-luminous-vivid-orange-to-vivid-red-gradient-background{background: var(--wp--preset--gradient--luminous-vivid-orange-to-vivid-red) !important;}
63.has-very-light-gray-to-cyan-bluish-gray-gradient-background{background: var(--wp--preset--gradient--very-light-gray-to-cyan-bluish-gray) !important;}.has-cool-to-warm-spectrum-gradient-background{background: var(--wp--preset--gradient--cool-to-warm-spectrum) !important;}.has-blush-light-purple-gradient-background{background: var(--wp--preset--gradient--blush-light-purple) !important;}.has-blush-bordeaux-gradient-background{background: var(--wp--preset--gradient--blush-bordeaux) !important;}.has-luminous-dusk-gradient-background{background: var(--wp--preset--gradient--luminous-dusk) !important;}.has-pale-ocean-gradient-background{background: var(--wp--preset--gradient--pale-ocean) !important;}.has-electric-grass-gradient-background{background: var(--wp--preset--gradient--electric-grass) !important;}.has-midnight-gradient-background{background: var(--wp--preset--gradient--midnight) !important;}.has-small-font-size{font-size: var(--wp--preset--font-size--small) !important;}.has-medium-font-size{font-size: var(--wp--preset--font-size--medium) !important;}.has-large-font-size{font-size: var(--wp--preset--font-size--large) !important;}.has-x-large-font-size{font-size: var(--wp--preset--font-size--x-large) !important;}
64/*# sourceURL=global-styles-inline-css */
65</style>
66
67<link rel='stylesheet' id='dashicons-css' href='https://the-gadgeteer.com/wp-includes/css/dashicons.min.css?ver=7.1.2' media='all' />
68<link rel='stylesheet' id='contact-form-7-css' href='https://the-gadgeteer.com/wp-content/plugins/contact-form-7/includes/css/styles.css?ver=6.1.7' media='all' />
69<link rel='stylesheet' id='dhnf-style-css' href='https://the-gadgeteer.com/wp-content/plugins/external-links-nofollow-open-in-new-tab-favicon/style.css?ver=7.1.2' media='all' />
70<link rel='stylesheet' id='stcr-font-awesome-css' href='https://the-gadgeteer.com/wp-content/plugins/subscribe-to-comments-reloaded/includes/css/font-awesome.min.css?ver=7.1.2' media='all' />
71<link rel='stylesheet' id='stcr-style-css' href='https://the-gadgeteer.com/wp-content/plugins/subscribe-to-comments-reloaded/includes/css/stcr-style.css?ver=7.1.2' media='all' />
72<style id="jetpack-stats-inline-css">
73img#wpstats{display:none}
74/*# sourceURL=jetpack-stats-inline-css */
75</style>
76<link rel='stylesheet' id='gadgeteer-css' href='https://the-gadgeteer.com/wp-content/themes/gadgeteer/assets/css/gadgeteer.css?ver=1790225847' media='all' />
77<link rel="https://api.w.org/" href="https://the-gadgeteer.com/wp-json/" /><link rel="alternate" title="JSON" type="application/json" href="https://the-gadgeteer.com/wp-json/wp/v2/posts/528663" /><link rel="EditURI" type="application/rsd+xml" title="RSD" href="https://the-gadgeteer.com/xmlrpc.php?rsd" />
78<meta name="generator" content="WordPress 7.1.2" />
79<link rel='shortlink' href='https://the-gadgeteer.com/?p=528663' />
80<style>
81.h-captcha{position:relative;display:block;margin-bottom:2rem;padding:0;clear:both}.h-captcha[data-size="normal"]{width:302px;height:76px}.h-captcha[data-size="compact"]{width:158px;height:138px}.h-captcha[data-size="invisible"]{display:none}.h-captcha iframe{z-index:1}.h-captcha::before{content:"";display:block;position:absolute;top:0;left:0;background:url(https://the-gadgeteer.com/wp-content/plugins/hcaptcha-for-forms-and-more/assets/images/hcaptcha-div-logo.svg) no-repeat;border:1px solid #fff0;border-radius:4px;box-sizing:border-box}.h-captcha::after{content:"If you see this message, hCaptcha failed to load due to site errors.";font-family:-apple-system,system-ui,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen,Ubuntu,"Helvetica Neue",Arial,sans-serif;font-size:10px;font-weight:500;position:absolute;top:0;bottom:0;left:0;right:0;box-sizing:border-box;color:#bf1722;opacity:0}.h-captcha.hcaptcha-api-delayed::after{content:"The hCaptcha loading is delayed until user interaction with the form.";color:#555}.h-captcha:not(:has(iframe))::after{animation:hcap-msg-fade-in .3s ease forwards;animation-delay:2s}.h-captcha.hcaptcha-api-delayed:not(:has(iframe))::after{animation-delay:0s}.h-captcha:has(iframe)::after{animation:none;opacity:0}
81@keyframes hcap-msg-fade-in{to{opacity:1}}.h-captcha[data-size="normal"]::before{width:302px;height:76px;background-position:93.8% 28%}.h-captcha[data-size="normal"]::after{width:302px;height:76px;display:flex;flex-wrap:wrap;align-content:center;line-height:normal;padding:0 75px 0 10px}.h-captcha[data-size="compact"]::before{width:158px;height:138px;background-position:49.9% 78.8%}.h-captcha[data-size="compact"]::after{width:158px;height:138px;text-align:center;line-height:normal;padding:24px 10px 10px 10px}.h-captcha[data-theme="light"]::before,body.is-light-theme .h-captcha[data-theme="auto"]::before,.h-captcha[data-theme="auto"]::before{background-color:#fafafa;border:1px solid #e0e0e0}.h-captcha[data-theme="dark"]::before,body.is-dark-theme .h-captcha[data-theme="auto"]::before,html.wp-dark-mode-active .h-captcha[data-theme="auto"]::before,html.drdt-dark-mode .h-captcha[data-theme="auto"]::before{background-image:url(https://the-gadgeteer.com/wp-content/plugins/hcaptcha-for-forms-and-more/assets/images/hcaptcha-div-logo-white.svg);background-repeat:no-repeat;background-color:#333;border:1px solid #f5f5f5}@media (prefers-color-scheme:dark){.h-captcha[data-theme="auto"]::before{background-image:url(https://the-gadgeteer.com/wp-content/plugins/hcaptcha-for-forms-and-more/assets/images/hcaptcha-div-logo-white.svg);background-repeat:no-repeat;background-color:#333;border:1px solid #f5f5f5}}.h-captcha[data-theme="custom"]::before{background-color:initial}.h-captcha[data-size="invisible"]::before,.h-captcha[data-size="invisible"]::after{display:none}.h-captcha iframe{position:relative}div[style*="z-index: 2147483647"] div[style*="border-width: 11px"][style*="position: absolute"][style*="pointer-events: none"]{border-style:none}
82</style>
83<style>
84span[data-name="hcap-cf7"] .h-captcha{margin-bottom:0}span[data-name="hcap-cf7"]~input[type="submit"],span[data-name="hcap-cf7"]~button[type="submit"]{margin-top:2rem}
85</style>
86
87<!-- Gadgeteer: site head scripts -->
88<!-- Google Analytics -->
vendor: 67 bytes, lines 88-89
88
89<script async="" src="https://www.googletagmanager.com/gtag/js?id=
89G-RRBRESCD59
vendor: 12 bytes, line 89
89"></script>
90<script>
91  
vendor: 133 bytes, lines 91-94
91window.dataLayer = window.dataLayer || [];
92  function gtag(){dataLayer.push(arguments);}
93  gtag('js', new Date());
94  gtag('config', '
94G-RRBRESCD59
vendor: 4 bytes, line 94
94');
95</script>
95
96<!-- Clicky -->
97<script async data-id="101496649" src="//static.getclicky.com/js"></script>
97
98<link rel="icon" href="https://the-gadgeteer.com/wp-content/themes/gadgeteer/assets/img/favicon.svg?ver=1790129023" type="image/svg+xml" sizes="any">
99<style>
100</style>
101<link rel='stylesheet' id='jetpack-swiper-library-css' href='https://the-gadgeteer.com/wp-content/plugins/jetpack/_inc/blocks/swiper.css?ver=16.2' media='all' />
102<link rel='stylesheet' id='jetpack-carousel-css' href='https://the-gadgeteer.com/wp-content/plugins/jetpack/modules/carousel/jetpack-carousel.css?ver=16.2' media='all' />
103
104</head>
105
106<body class="wp-singular post-template-default single single-post postid-528663 single-format-standard wp-embed-responsive wp-theme-gadgeteer is-reading is-article gadgeteer-has-sidebar">
107<a class="skip-link screen-reader-text" href="#content">Skip to content</a>
108
109<div id="page" class="site">
110	<header id="masthead" class="site-header site-header--reading">
111		<div class="site-header__inner">
112			<a class="brand brand--compact" href="https://the-gadgeteer.com/" rel="home"><img class="brand__logo" src="https://the-gadgeteer.com/wp-content/themes/gadgeteer/assets/img/gadgeteer-logo.svg" width="2072" height="300" alt=""><span class="screen-reader-text">The Gadgeteer – home</span></a>
113							<nav class="reading-crumb" aria-label="Breadcrumb"><ol class="reading-crumb__list"><li><a href="https://the-gadgeteer.com/category/articles/">Articles</a></li><li><a href="https://the-gadgeteer.com/tag/chromebook/">chromebook</a></li><li aria-current="page"><span>5 Reasons Googlebook OS Could Be Google’s Most Interesting Laptop Move Yet</span></li></ol></nav>				<div class="reading-progress" aria-hidden="true"><span class="reading-progress__bar"></span></div>
114			
115			<nav id="site-navigation" class="main-navigation" aria-label="Primary">
116				<ul id="primary-menu" class="menu primary-menu"><li id="menu-item-220961" class="menuheader menu-item menu-item-type-custom menu-item-object-custom menu-item-220961"><a href="https://the-gadgeteer.com/category/reviews/">Reviews</a></li>
117<li id="menu-item-233577" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-has-children menu-item-233577"><a>Articles</a><button class="submenu-toggle" type="button" aria-expanded="false" aria-label="Show submenu of Articles"><svg class="icon" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="m6 9 6 6 6-6"/></svg></button>
118<ul class="sub-menu">
119	<li id="menu-item-220991" class="menu-item menu-item-type-taxonomy menu-item-object-category current-post-ancestor current-menu-parent current-post-parent menu-item-220991"><a href="https://the-gadgeteer.com/category/articles/">&#8230; all Articles</a></li>
120	<li id="menu-item-233366" class="menu-item menu-item-type-taxonomy menu-item-object-category menu-item-233366"><a href="https://the-gadgeteer.com/category/news/">&#8230; all News</a></li>
121	<li id="menu-item-382635" class="menu-item menu-item-type-taxonomy menu-item-object-post_tag menu-item-382635 menu-item-signal"><a href="https://the-gadgeteer.com/tag/deal/">&#8230; all Deals</a></li>
122</ul>
123</li>
124<li id="menu-item-382634" class="menu-item menu-item-type-taxonomy menu-item-object-post_tag menu-item-382634 menu-item-signal"><a href="https://the-gadgeteer.com/category/deals/">Deals</a></li>
125<li id="menu-item-495790" class="menu-item menu-item-type-taxonomy menu-item-object-category menu-item-495790"><a href="https://the-gadgeteer.com/category/buyers-guide/">Buyer&#8217;s Guide</a></li>
126<li id="menu-item-217896" class="menuheader menu-item menu-item-type-taxonomy menu-item-object-post_tag menu-item-has-children menu-item-217896 menu-item-extra"><a href="https://the-gadgeteer.com/tag/edc/">EDC</a><button class="submenu-toggle" type="button" aria-expanded="false" aria-label="Show submenu of EDC"><svg class="icon" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="m6 9 6 6 6-6"/></svg></button>
127<ul class="sub-menu">
128	<li id="menu-item-218132" class="menu-item menu-item-type-taxonomy menu-item-object-post_tag menu-item-218132"><a href="https://the-gadgeteer.com/tag/edc/">&#8230; all EDC gear</a></li>
129	<li id="menu-item-227435" class="menuheader menu-item menu-item-type-custom menu-item-object-custom menu-item-has-children menu-item-227435"><a>Bags</a><button class="submenu-toggle" type="button" aria-expanded="false" aria-label="Show submenu of Bags"><svg class="icon" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false">
129<path d="m6 9 6 6 6-6"/></svg></button>
130	<ul class="sub-menu">
131		<li id="menu-item-227436" class="menu-item menu-item-type-taxonomy menu-item-object-post_tag menu-item-227436"><a href="https://the-gadgeteer.com/tag/backpack/">Backpacks</a></li>
132		<li id="menu-item-227438" class="menu-item menu-item-type-taxonomy menu-item-object-post_tag menu-item-227438"><a href="https://the-gadgeteer.com/tag/camera-bag/">Camera bags</a></li>
133		<li id="menu-item-227440" class="menu-item menu-item-type-taxonomy menu-item-object-post_tag menu-item-227440"><a href="https://the-gadgeteer.com/tag/luggage/">Luggage</a></li>
134		<li id="menu-item-227437" class="menu-item menu-item-type-taxonomy menu-item-object-post_tag menu-item-227437"><a href="https://the-gadgeteer.com/tag/messenger-bag/">Messenger bags</a></li>
135		<li id="menu-item-227439" class="menu-item menu-item-type-taxonomy menu-item-object-post_tag menu-item-227439"><a href="https://the-gadgeteer.com/tag/shoulder-bag/">Shoulder bags</a></li>
136		<li id="menu-item-217897" class="menu-item menu-item-type-taxonomy menu-item-object-post_tag menu-item-217897"><a href="https://the-gadgeteer.com/tag/bags-2/">&#8230; All Bags</a></li>
137	</ul>
138</li>
139	<li id="menu-item-220895" class="menu-item menu-item-type-taxonomy menu-item-object-post_tag menu-item-220895"><a href="https://the-gadgeteer.com/tag/flashlight/">Flashlights</a></li>
140	<li id="menu-item-218116" class="menu-item menu-item-type-taxonomy menu-item-object-post_tag menu-item-218116"><a href="https://the-gadgeteer.com/tag/keychain/">Keychain</a></li>
141	<li id="menu-item-219121" class="menu-item menu-item-type-taxonomy menu-item-object-post_tag menu-item-219121"><a href="https://the-gadgeteer.com/tag/knives/">Knives</a></li>
142	<li id="menu-item-219122" class="menu-item menu-item-type-taxonomy menu-item-object-post_tag menu-item-219122"><a href="https://the-gadgeteer.com/tag/multi-tool/">Multi-tools</a></li>
143	<li id="menu-item-218122" class="menu-item menu-item-type-taxonomy menu-item-object-post_tag menu-item-218122"><a href="https://the-gadgeteer.com/tag/notebooks/">Notebooks</a></li>
144	<li id="menu-item-218120" class="menu-item menu-item-type-taxonomy menu-item-object-post_tag menu-item-218120"><a href="https://the-gadgeteer.com/tag/pencil/">Pencils</a></li>
145	<li id="menu-item-218121" class="menu-item menu-item-type-taxonomy menu-item-object-post_tag menu-item-218121"><a href="https://the-gadgeteer.com/tag/pens/">Pens</a></li>
146	<li id="menu-item-218117" class="menu-item menu-item-type-taxonomy menu-item-object-post_tag menu-item-218117"><a href="https://the-gadgeteer.com/tag/pocket-gear/">Pocket Gear</a></li>
147	<li id="menu-item-217280" class="menu-item menu-item-type-taxonomy menu-item-object-post_tag menu-item-217280"><a href="https://the-gadgeteer.com/tag/wallets/">Wallets</a></li>
148	<li id="menu-item-217264" class="menu-item menu-item-type-taxonomy menu-item-object-post_tag menu-item-217264"><a href="https://the-gadgeteer.com/tag/watches/">Watches</a></li>
149</ul>
150</li>
151<li id="menu-item-220953" class="menuheader menu-item menu-item-type-custom menu-item-object-custom menu-item-has-children menu-item-220953 menu-item-more"><a>More</a><button class="submenu-toggle" type="button" aria-expanded="false" aria-label="Show submenu of More"><svg class="icon" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="m6 9 6 6 6-6"/></svg></button>
152<ul class="sub-menu">
153	<li id="menu-item-359134" class="menu-item menu-item-type-taxonomy menu-item-object-post_tag menu-item-359134"><a href="https://the-gadgeteer.com/tag/3d-printing/">3D printers</a></li>
154	<li id="menu-item-220963" class="menu-item menu-item-type-taxonomy menu-item-object-post_tag menu-item-220963"><a href="https://the-gadgeteer.com/tag/audio_video_gear/">Audio, Video, TV</a></li>
155	<li id="menu-item-217262" class="menuheader menu-item menu-item-type-taxonomy menu-item-object-post_tag menu-item-has-children menu-item-217262"><a href="https://the-gadgeteer.com/tag/bluetooth/">Bluetooth</a><button class="submenu-toggle" type="button" aria-expanded="false" aria-label="Show submenu of Bluetooth"><svg class="icon" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false">
155<path d="m6 9 6 6 6-6"/></svg></button>
156	<ul class="sub-menu">
157		<li id="menu-item-218128" class="menu-item menu-item-type-taxonomy menu-item-object-post_tag menu-item-218128"><a href="https://the-gadgeteer.com/tag/bluetooth-audio-adapter/">Bluetooth audio adapters</a></li>
158		<li id="menu-item-217901" class="menu-item menu-item-type-taxonomy menu-item-object-post_tag menu-item-217901"><a href="https://the-gadgeteer.com/tag/bluetooth-earbuds/">Bluetooth earbuds</a></li>
159		<li id="menu-item-217899" class="menu-item menu-item-type-taxonomy menu-item-object-post_tag menu-item-217899"><a href="https://the-gadgeteer.com/tag/bluetooth-headphones/">Bluetooth headphones</a></li>
160		<li id="menu-item-217900" class="menu-item menu-item-type-taxonomy menu-item-object-post_tag menu-item-217900"><a href="https://the-gadgeteer.com/tag/bluetooth-headset/">Bluetooth headsets</a></li>
161		<li id="menu-item-217898" class="menu-item menu-item-type-taxonomy menu-item-object-post_tag menu-item-217898"><a href="https://the-gadgeteer.com/tag/bluetooth-speaker/">Bluetooth speakers</a></li>
162		<li id="menu-item-218129" class="menu-item menu-item-type-taxonomy menu-item-object-post_tag menu-item-218129"><a href="https://the-gadgeteer.com/tag/bluetooth-keyboard/">Bluetooth keyboards</a></li>
163		<li id="menu-item-218130" class="menu-item menu-item-type-taxonomy menu-item-object-post_tag menu-item-218130"><a href="https://the-gadgeteer.com/tag/bluetooth-mouse/">Bluetooth mice</a></li>
164		<li id="menu-item-218127" class="menu-item menu-item-type-taxonomy menu-item-object-post_tag menu-item-218127"><a href="https://the-gadgeteer.com/tag/bluetooth/">&#8230; all Bluetooth gear</a></li>
165	</ul>
166</li>
167	<li id="menu-item-244581" class="menu-item menu-item-type-taxonomy menu-item-object-post_tag menu-item-244581"><a href="https://the-gadgeteer.com/tag/car_gear/">Car Gear</a></li>
168	<li id="menu-item-377376" class="menu-item menu-item-type-taxonomy menu-item-object-post_tag menu-item-377376"><a href="https://the-gadgeteer.com/tag/electric-bike/">Electric Bike</a></li>
169	<li id="menu-item-220964" class="menu-item menu-item-type-taxonomy menu-item-object-post_tag menu-item-220964"><a href="https://the-gadgeteer.com/tag/gaming-gear/">Gaming Gear</a></li>
170	<li id="menu-item-345970" class="menu-item menu-item-type-taxonomy menu-item-object-post_tag menu-item-345970"><a href="https://the-gadgeteer.com/tag/graphics-tablet/">Graphics tablets</a></li>
171	<li id="menu-item-220954" class="menu-item menu-item-type-taxonomy menu-item-object-post_tag menu-item-220954"><a href="https://the-gadgeteer.com/tag/home_tech/">Home and Kitchen</a></li>
172	<li id="menu-item-375049" class="menu-item menu-item-type-taxonomy menu-item-object-post_tag menu-item-375049"><a href="https://the-gadgeteer.com/tag/mechanical-keyboard/">Mechanical keyboards</a></li>
173	<li id="menu-item-220959" class="menu-item menu-item-type-taxonomy menu-item-object-post_tag menu-item-220959"><a href="https://the-gadgeteer.com/tag/outdoor-gear/">Outdoor Gear</a></li>
174	<li id="menu-item-218249" class="menu-item menu-item-type-taxonomy menu-item-object-post_tag menu-item-218249"><a href="https://the-gadgeteer.com/tag/pet-gadgets/">Pets</a></li>
175	<li id="menu-item-353590" class="menu-item menu-item-type-taxonomy menu-item-object-post_tag menu-item-353590"><a href="https://the-gadgeteer.com/tag/power-station/">Power Stations</a></li>
176	<li id="menu-item-220960" class="menu-item menu-item-type-taxonomy menu-item-object-post_tag menu-item-220960"><a href="https://the-gadgeteer.com/tag/travel_gear/">Travel Gear</a></li>
177	<li id="menu-item-217263" class="menu-item menu-item-type-taxonomy menu-item-object-post_tag menu-item-217263"><a href="https://the-gadgeteer.com/tag/toys/">Toys</a></li>
178</ul>
179</li>
180</ul>			</nav>
181
182			<div class="site-header__tools">
183				<form role="search" method="get" class="header-search" action="https://the-gadgeteer.com/">
184					<label class="screen-reader-text" for="header-search-field">Search</label>
185					<span class="header-search__icon" aria-hidden="true"></span>
186					<input type="search" id="header-search-field" class="header-search__field" name="s" value="" placeholder="Search">
187					<button type="submit" class="header-search__submit"><svg class="icon" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><circle cx="11" cy="11" r="7"/><path d="m20 20-3.5-3.5"/></svg><span class="screen-reader-text">Search</span></button>
188				</form>
189													<a class="btn btn--pill subscribe-button" href="https://the-gadgeteer.com/subscribe/">Subscribe</a>
190							</div>
191			<button class="mobile-menu-toggle" type="button" aria-expanded="false" aria-controls="mobile-menu-drawer" aria-haspopup="dialog">
192				<svg class="icon" width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" aria-hidden="true" focusable="false">
192<path d="M4 7h16M4 12h16M4 17h16"/></svg>				<span class="screen-reader-text">Open menu</span>
193			</button>
194		</div>
195	</header>
196	<dialog id="mobile-menu-drawer" class="mobile-menu-drawer" aria-label="Site menu">
197		<div class="mobile-menu-drawer__header">
198			<a class="brand brand--drawer" href="https://the-gadgeteer.com/" rel="home"><img class="brand__logo" src="https://the-gadgeteer.com/wp-content/themes/gadgeteer/assets/img/gadgeteer-logo.svg" width="2072" height="300" alt=""><span class="screen-reader-text">The Gadgeteer – home</span></a>			<button class="mobile-menu-close" type="button" autofocus>
199				<svg class="icon" width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" aria-hidden="true" focusable="false"><path d="M6 6l12 12M18 6 6 18"/></svg>				<span class="screen-reader-text">Close menu</span>
200			</button>
201		</div>
202		<div class="mobile-menu-drawer__navigation"></div>
203		<div class="mobile-menu-drawer__tools"></div>
204	</dialog>
205	
206	<div id="content" class="site-content">
207<main id="main" class="site-main site-main--single site-main--article">
208	<article id="post-528663" class="entry entry--single entry--article post-528663 post type-post status-publish format-standard has-post-thumbnail hentry category-articles tag-chromebook tag-computer tag-google tag-laptop">
209	<header class="entry-header">
210					<div class="kicker kicker--entry"><a class="kicker__cat" href="https://the-gadgeteer.com/category/articles/">Articles</a><span class="kicker__sep" aria-hidden="true">·</span><a class="kicker__tag" href="https://the-gadgeteer.com/tag/chromebook/">chromebook</a><span class="kicker__sep" aria-hidden="true">·</span><a class="kicker__tag" href="https://the-gadgeteer.com/tag/computer/">computer</a></div>				<h1 class="entry-title">5 Reasons Googlebook OS Could Be Google’s Most Interesting Laptop Move Yet</h1>						<div class="byline-card">
211		<a class="byline-card__avatar" href="https://the-gadgeteer.com/author/rei/" aria-hidden="true" tabindex="-1"><span class="avatar-initials" aria-hidden="true">RP</span></a>
212		<div class="byline-card__text">
213			<a class="byline-card__name" rel="author" href="https://the-gadgeteer.com/author/rei/"><span class="screen-reader-text">By </span>Rei Padla</a>
214			<span class="byline-card__meta">
215				<time datetime="2026-09-24T05:30:49-05:00">September 24, 2026</time>
216				<span class="kicker__sep" aria-hidden="true">·</span>
217				<span>7 min read</span>
218							</span>
219		</div>
220	</div>
221				</header>
222
223			<figure class="entry-hero">
224			<img width="860" height="645" src="https://the-gadgeteer.com/wp-content/uploads/2026/09/GoogleBook-OS-Cover-1280x960.jpeg" class="entry-hero__img wp-post-image" alt="GoogleBook OS" loading="eager" fetchpriority="high" decoding="async" sizes="(max-width: 1240px) 100vw, 1184px" srcset="https://the-gadgeteer.com/wp-content/uploads/2026/09/GoogleBook-OS-Cover-1280x960.jpeg 1280w, https://the-gadgeteer.com/wp-content/uploads/2026/09/GoogleBook-OS-Cover-800x600.jpeg 800w, https://the-gadgeteer.com/wp-content/uploads/2026/09/GoogleBook-OS-Cover-768x576.jpeg 768w, https://the-gadgeteer.com/wp-content/uploads/2026/09/GoogleBook-OS-Cover.jpeg 1440w" data-attachment-id="528674" data-permalink="https://the-gadgeteer.com/2026/09/24/5-things-to-love-about-the-new-googlebook-os/screenshot-1654/" data-orig-file="https://the-gadgeteer.com/wp-content/uploads/2026/09/GoogleBook-OS-Cover.jpeg" data-orig-size="1440,1080" data-comments-opened="1" data-image-title="GoogleBook OS" data-image-description="" data-image-caption="" data-large-file="https://the-gadgeteer.com/wp-content/uploads/2026/09/GoogleBook-OS-Cover-1280x960.jpeg" />					</figure>
225	
226	
227	<div class="entry-layout has-aside">
228		<div class="entry-main">
229			<div class="entry-content">
230				<div class='code-block code-block-4' style='margin: 8px 0; clear: both;'>
231<center class="disclaimer">If you buy something from a link in this article, we may earn a commission. <a href="https://the-gadgeteer.com/disclosure/">Learn more</a></center></div>
232<p>Android phone owners have plenty of Windows laptops and Chromebooks to choose from, but moving between phone and computer can still feel like moving between separate worlds. Files need to be transferred, mobile apps may not exist on the laptop, and even Google’s own services can behave differently depending on which screen you are using.</p>
233<p>Googlebook OS is Google’s attempt to make that relationship much tighter. It is built on Android technology while incorporating desktop foundations developed through ChromeOS, giving Google a way to combine Android apps and phone integration with a desktop-class Chrome browser, desktop windowing, and laptop hardware.</p>
234<p>The first Googlebooks come from Acer, ASUS, Dell, HP, and Lenovo, with prices starting at $899. They reach U.S. stores on October 4, followed by several additional countries on October 5. The hardware will determine performance and battery life, but Googlebook OS is what makes these machines feel different from just another wave of Chromebooks.</p><div class='code-block code-block-10' style='margin: 8px 0; clear: both;'>
235<br>
236<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-8065766046515397"
237     crossorigin="anonymous"></script>
237
238<!-- TGT-ARTICLE-1 -->
239<ins class="adsbygoogle"
240     style="display:block"
241     data-ad-client="ca-pub-8065766046515397"
242     data-ad-slot="8818340660"
243     data-ad-format="auto"
244     data-full-width-responsive="true"></ins>
245<script>
246     (adsbygoogle = window.adsbygoogle || []).push({});
247</script>
247
248<br></div>
249
250<p>Here are five features that give Google’s new platform a particularly interesting start.</p>
251<div class="review-price" style="display: flex; justify-content: space-between; align-items: center;">
252<div><strong>Add The Gadgeteer on Google</strong> Add The Gadgeteer as a preferred source to see more of our coverage on Google.</div>
253<p><a style="display: inline-block; border: 2px solid #2d6a4f; padding: 10px 24px; text-decoration: none; color: #2d6a4f; font-weight: bold; letter-spacing: 2px; white-space: nowrap;" href="https://www.google.com/preferences/source?q=the-gadgeteer.com" target="_blank" rel="noopener">ADD US ON GOOGLE</a></p>
254</div>
255<h2 id="1-your-android-phone-becomes-part-of-the-laptop-experience">1. Your Android phone becomes part of the laptop experience</h2>
256<p>Googlebook OS makes its strongest argument before AI even enters the discussion. Google has built several cross-device features around Android phones into the experience, including Continue On, Quick Access in the Files app, and Cast My Apps. Each addresses a different part of the phone-to-laptop transition.</p>
257<p><img decoding="async" data-attachment-id="528671" data-permalink="https://the-gadgeteer.com/2026/09/24/5-things-to-love-about-the-new-googlebook-os/screenshot-1651/" data-orig-file="https://the-gadgeteer.com/wp-content/uploads/2026/09/GoogleBook-OS-4.jpeg" data-orig-size="1440,935" data-comments-opened="1" data-image-title="GoogleBook OS" data-image-description="" data-image-caption="" data-large-file="https://the-gadgeteer.com/wp-content/uploads/2026/09/GoogleBook-OS-4-1280x831.jpeg" class="aligncenter size-full wp-image-528671" src="https://the-gadgeteer.com/wp-content/uploads/2026/09/GoogleBook-OS-4.jpeg" alt="GoogleBook OS" width="1440" height="935" srcset="https://the-gadgeteer.com/wp-content/uploads/2026/09/GoogleBook-OS-4.jpeg 1440w, https://the-gadgeteer.com/wp-content/uploads/2026/09/GoogleBook-OS-4-800x519.jpeg 800w, https://the-gadgeteer.com/wp-content/uploads/2026/09/GoogleBook-OS-4-1280x831.jpeg 1280w, https://the-gadgeteer.com/wp-content/uploads/2026/09/GoogleBook-OS-4-768x499.jpeg 768w" sizes="(max-width: 1440px) 100vw, 1440px">Continue On lets supported tasks move from your phone to the Googlebook. The Files app can display, search, and open files and photos stored on your phone, reducing the need to email something to yourself or manually upload it to cloud storage first.</p><div class='code-block code-block-11' style='margin: 8px 0; clear: both;'>
258<br>
259<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-8065766046515397"
260     crossorigin="anonymous"></script>
260
261<!-- TGT-ARTICLE-2 -->
262<ins class="adsbygoogle"
263     style="display:block"
264     data-ad-client="ca-pub-8065766046515397"
265     data-ad-slot="9064369787"
266     data-ad-format="auto"
267     data-full-width-responsive="true"></ins>
268<script>
269     (adsbygoogle = window.adsbygoogle || []).push({});
270</script>
270
271<br><br></div>
272
273<p>Cast My Apps takes a different approach. Instead of installing another copy of a mobile app on the computer, it streams the app from your phone into a desktop window where you can interact with it. Google gives examples such as checking a delivery app or retrieving a one-time code from Messages without picking up your phone.</p>
274<p>These are capabilities Google describes rather than proof that every Android phone, app, and workflow will behave flawlessly. Their practical value will depend on reliability and compatibility. Still, they address a genuine problem: making your phone feel less like a separate device whenever you sit down at your computer.</p>
275<h2 id="2-magic-pointer-brings-gemini-to-whatever-youre-doing">2. Magic Pointer brings Gemini to whatever you’re doing</h2>
276<p>AI features on laptops can create their own kind of friction. If getting help requires opening a chatbot, describing what is already on the screen, copying the result, and returning to the original app, the AI may add almost as many steps as it removes.</p>
277<p>Magic Pointer is Google’s attempt to change that interaction. A quick wiggle of the cursor brings Gemini to the content you are already viewing. Google says Magic Pointer can understand text, images, and surrounding context, allowing you to select something and ask Gemini to work with it.</p><div class='code-block code-block-11' style='margin: 8px 0; clear: both;'>
278<br>
279<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-8065766046515397"
280     crossorigin="anonymous"></script>
280
281<!-- TGT-ARTICLE-2 -->
282<ins class="adsbygoogle"
283     style="display:block"
284     data-ad-client="ca-pub-8065766046515397"
285     data-ad-slot="9064369787"
286     data-ad-format="auto"
287     data-full-width-responsive="true"></ins>
288<script>
289     (adsbygoogle = window.adsbygoogle || []).push({});
290</script>
290
291<br><br></div>
292
293<p><img decoding="async" data-attachment-id="528666" data-permalink="https://the-gadgeteer.com/2026/09/24/5-things-to-love-about-the-new-googlebook-os/screenshot-1646/" data-orig-file="https://the-gadgeteer.com/wp-content/uploads/2026/09/GoogleBook-OS-9.jpeg" data-orig-size="1440,896" data-comments-opened="1" data-image-title="GoogleBook OS" data-image-description="" data-image-caption="" data-large-file="https://the-gadgeteer.com/wp-content/uploads/2026/09/GoogleBook-OS-9-1280x796.jpeg" class="aligncenter size-full wp-image-528666" src="https://the-gadgeteer.com/wp-content/uploads/2026/09/GoogleBook-OS-9.jpeg" alt="GoogleBook OS" width="1440" height="896" srcset="https://the-gadgeteer.com/wp-content/uploads/2026/09/GoogleBook-OS-9.jpeg 1440w, https://the-gadgeteer.com/wp-content/uploads/2026/09/GoogleBook-OS-9-800x498.jpeg 800w, https://the-gadgeteer.com/wp-content/uploads/2026/09/GoogleBook-OS-9-1280x796.jpeg 1280w, https://the-gadgeteer.com/wp-content/uploads/2026/09/GoogleBook-OS-9-768x478.jpeg 768w" sizes="(max-width: 1440px) 100vw, 1440px">Google’s examples include translating text, organizing calendar details, working with images, and handling contextual tasks without constantly jumping between windows. Google says Magic Pointer is integrated directly into the Googlebook interface, although its Gemini responses will still depend on the strengths and limitations of generative AI.</p>
294<p>That distinction matters. Magic Pointer does not make Gemini automatically accurate simply because it is closer to your cursor. Its stronger advantage is reducing the friction of asking for AI help while you are already working.</p>
295<h2 id="3-android-apps-and-desktop-chrome-share-the-same-foundation">3. Android apps and desktop Chrome share the same foundation</h2>
296<p>Chromebooks have supported Android apps for years, but ChromeOS began life as a web-focused operating system and added Android software later. Googlebook OS reverses that relationship by building on Android technology while bringing over desktop foundations from ChromeOS.</p>
297<p><img decoding="async" data-attachment-id="528673" data-permalink="https://the-gadgeteer.com/2026/09/24/5-things-to-love-about-the-new-googlebook-os/screenshot-1653/" data-orig-file="https://the-gadgeteer.com/wp-content/uploads/2026/09/GoogleBook-OS-2.jpeg" data-orig-size="1440,639" data-comments-opened="1" data-image-title="GoogleBook OS" data-image-description="" data-image-caption="" data-large-file="https://the-gadgeteer.com/wp-content/uploads/2026/09/GoogleBook-OS-2-1280x568.jpeg" class="aligncenter size-full wp-image-528673" src="https://the-gadgeteer.com/wp-content/uploads/2026/09/GoogleBook-OS-2.jpeg" alt="GoogleBook OS" width="1440" height="639" srcset="https://the-gadgeteer.com/wp-content/uploads/2026/09/GoogleBook-OS-2.jpeg 1440w, https://the-gadgeteer.com/wp-content/uploads/2026/09/GoogleBook-OS-2-800x355.jpeg 800w, https://the-gadgeteer.com/wp-content/uploads/2026/09/GoogleBook-OS-2-1280x568.jpeg 1280w, https://the-gadgeteer.com/wp-content/uploads/2026/09/GoogleBook-OS-2-768x341.jpeg 768w" sizes="(max-width: 1440px) 100vw, 1440px">That gives users access to millions of Play Store apps alongside a desktop-class version of Chrome with extension support. Google specifically highlights software including Adobe Photoshop, Adobe Lightroom, and CapCut, as well as entertainment apps with offline viewing support.</p><div class='code-block code-block-11' style='margin: 8px 0; clear: both;'>
298<br>
299<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-8065766046515397"
300     crossorigin="anonymous"></script>
300
301<!-- TGT-ARTICLE-2 -->
302<ins class="adsbygoogle"
303     style="display:block"
304     data-ad-client="ca-pub-8065766046515397"
305     data-ad-slot="9064369787"
306     data-ad-format="auto"
307     data-full-width-responsive="true"></ins>
308<script>
309     (adsbygoogle = window.adsbygoogle || []).push({});
310</script>
310
311<br><br></div>
312
313<p>The practical appeal here is flexibility. A Googlebook can use a desktop website when that provides the better experience and an Android app when mobile software offers features that the browser version lacks. For someone already invested in Android, that could make the laptop feel more familiar from the moment it is set up.</p>
314<p>There is an important limitation. Millions of available Android apps do not equal millions of excellent laptop apps. Interfaces originally created for a phone may still need optimization for large displays, keyboards, touchpads, and resizable windows. Early hands-on impressions suggest that Googlebook OS feels recognizably like Android adapted for desktop use, but the quality of individual apps will still vary.</p>
315<h2 id="4-linux-gives-googlebook-os-room-to-do-serious-work">4. Linux gives Googlebook OS room to do serious work</h2>
316<p>An Android-based laptop could easily sound limiting to developers who depend on terminals, repositories, command-line tools, and conventional Linux software. Google has addressed that concern by including an isolated Linux environment with full terminal access.</p>
317<p>Google says developers can pull code repositories, run Linux development tools, and use software such as Claude Code and Antigravity CLI. Googlebook includes Antigravity, Google’s AI agent development platform, for building, testing, and deploying apps.</p><div class='code-block code-block-11' style='margin: 8px 0; clear: both;'>
318<br>
319<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-8065766046515397"
320     crossorigin="anonymous"></script>
320
321<!-- TGT-ARTICLE-2 -->
322<ins class="adsbygoogle"
323     style="display:block"
324     data-ad-client="ca-pub-8065766046515397"
325     data-ad-slot="9064369787"
326     data-ad-format="auto"
327     data-full-width-responsive="true"></ins>
328<script>
329     (adsbygoogle = window.adsbygoogle || []).push({});
330</script>
330
331<br><br></div>
332
333<p><img loading="lazy" decoding="async" data-attachment-id="528672" data-permalink="https://the-gadgeteer.com/2026/09/24/5-things-to-love-about-the-new-googlebook-os/screenshot-1652/" data-orig-file="https://the-gadgeteer.com/wp-content/uploads/2026/09/GoogleBook-OS-3.jpeg" data-orig-size="1440,884" data-comments-opened="1" data-image-title="GoogleBook OS" data-image-description="" data-image-caption="" data-large-file="https://the-gadgeteer.com/wp-content/uploads/2026/09/GoogleBook-OS-3-1280x786.jpeg" class="aligncenter size-full wp-image-528672" src="https://the-gadgeteer.com/wp-content/uploads/2026/09/GoogleBook-OS-3.jpeg" alt="GoogleBook OS" width="1440" height="884" srcset="https://the-gadgeteer.com/wp-content/uploads/2026/09/GoogleBook-OS-3.jpeg 1440w, https://the-gadgeteer.com/wp-content/uploads/2026/09/GoogleBook-OS-3-800x491.jpeg 800w, https://the-gadgeteer.com/wp-content/uploads/2026/09/GoogleBook-OS-3-1280x786.jpeg 1280w, https://the-gadgeteer.com/wp-content/uploads/2026/09/GoogleBook-OS-3-768x471.jpeg 768w" sizes="auto, (max-width: 1440px) 100vw, 1440px">Security is part of the design. Google says the Linux environment runs through a Level 5 security-certified pKVM hypervisor, isolating it from the primary system. The broader platform also inherits ChromeOS security foundations, including Google Titan hardware root of trust, defense-in-depth protections, and on-device malware detection.</p>
334<p>Independent testing still needs to establish how well demanding development environments perform across the different Googlebook processors and configurations. Even so, full terminal access substantially expands what an Android-based computer can realistically be used for and gives technical users somewhere to turn when an Android app or web tool is not enough.</p>
335<h2 id="5-google-is-promising-up-to-10-years-of-updates">5. Google is promising up to 10 years of updates</h2>
336<p>A new platform can be a risky buy, especially at $899 or more. Google aims to ease that concern with regular feature drops and updates for up to 10 years.</p>
337<p>That matters because Googlebook OS will likely evolve after launch, from Magic Pointer and phone integration to desktop Android apps and development tools. “Up to 10 years” is not a guarantee of identical support for every device, but the commitment signals that Google intends to invest in the platform beyond launch.</p><div class='code-block code-block-11' style='margin: 8px 0; clear: both;'>
338<br>
339<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-8065766046515397"
340     crossorigin="anonymous"></script>
340
341<!-- TGT-ARTICLE-2 -->
342<ins class="adsbygoogle"
343     style="display:block"
344     data-ad-client="ca-pub-8065766046515397"
345     data-ad-slot="9064369787"
346     data-ad-format="auto"
347     data-full-width-responsive="true"></ins>
348<script>
349     (adsbygoogle = window.adsbygoogle || []).push({});
350</script>
350
351<br><br></div>
352
353<h2 id="who-should-be-excited-about-googlebook-os"><img loading="lazy" decoding="async" data-attachment-id="528667" data-permalink="https://the-gadgeteer.com/2026/09/24/5-things-to-love-about-the-new-googlebook-os/screenshot-1647/" data-orig-file="https://the-gadgeteer.com/wp-content/uploads/2026/09/GoogleBook-OS-8.jpeg" data-orig-size="1440,783" data-comments-opened="1" data-image-title="GoogleBook OS" data-image-description="" data-image-caption="" data-large-file="https://the-gadgeteer.com/wp-content/uploads/2026/09/GoogleBook-OS-8-1280x696.jpeg" class="aligncenter size-full wp-image-528667" src="https://the-gadgeteer.com/wp-content/uploads/2026/09/GoogleBook-OS-8.jpeg" alt="GoogleBook OS" width="1440" height="783" srcset="https://the-gadgeteer.com/wp-content/uploads/2026/09/GoogleBook-OS-8.jpeg 1440w, https://the-gadgeteer.com/wp-content/uploads/2026/09/GoogleBook-OS-8-800x435.jpeg 800w, https://the-gadgeteer.com/wp-content/uploads/2026/09/GoogleBook-OS-8-1280x696.jpeg 1280w, https://the-gadgeteer.com/wp-content/uploads/2026/09/GoogleBook-OS-8-768x418.jpeg 768w" sizes="auto, (max-width: 1440px) 100vw, 1440px">Who should be excited about Googlebook OS?</h2>
354<p>Googlebook OS makes the strongest early case for Android users who want more desktop capability than they expect from a traditional Chromebook. Continue On, Quick Access, and Cast My Apps ease the everyday friction of moving between devices, while Magic Pointer aims to make Gemini more useful without sending users to a separate AI workflow.</p>
355<p>Its Android foundation opens the door to a vast app ecosystem, while desktop Chrome and an isolated Linux environment keep the platform from relying solely on mobile apps. Google’s promise of updates for up to 10 years also gives the company time to refine the experience after launch.</p>
356<p>Questions remain. Android apps must prove they work consistently well on laptops, Gemini must be accurate as well as convenient, and the Linux environment needs broader real-world testing before it can be viewed as a replacement for an established development workstation.</p>
357<div data-carousel-extra='{"blog_id":1,"permalink":"https://the-gadgeteer.com/2026/09/24/5-things-to-love-about-the-new-googlebook-os/"}' id="gallery-1" class="gallery galleryid-528663 gallery-columns-3 gallery-size-thumbnail"><figure class="gallery-item">
358			<div class="gallery-icon landscape">
359				<a href="https://the-gadgeteer.com/2026/09/24/5-things-to-love-about-the-new-googlebook-os/screenshot-1645/"><img loading="lazy" decoding="async" width="250" height="250" src="https://the-gadgeteer.com/wp-content/uploads/2026/09/GoogleBook-OS-250x250.jpeg" class="attachment-thumbnail size-thumbnail" alt="GoogleBook OS" data-attachment-id="528665" data-permalink="https://the-gadgeteer.com/2026/09/24/5-things-to-love-about-the-new-googlebook-os/screenshot-1645/" data-orig-file="https://the-gadgeteer.com/wp-content/uploads/2026/09/GoogleBook-OS.jpeg" data-orig-size="1440,742" data-comments-opened="1" data-image-title="GoogleBook OS" data-image-description="" data-image-caption="" data-large-file="https://the-gadgeteer.com/wp-content/uploads/2026/09/GoogleBook-OS-1280x660.jpeg"></a>
360			</div></figure><figure class="gallery-item">
361			<div class="gallery-icon landscape">
362				<a href="https://the-gadgeteer.com/2026/09/24/5-things-to-love-about-the-new-googlebook-os/screenshot-1646/"><img loading="lazy" decoding="async" width="250" height="250" src="https://the-gadgeteer.com/wp-content/uploads/2026/09/GoogleBook-OS-9-250x250.jpeg" class="attachment-thumbnail size-thumbnail" alt="GoogleBook OS" data-attachment-id="528666" data-permalink="https://the-gadgeteer.com/2026/09/24/5-things-to-love-about-the-new-googlebook-os/screenshot-1646/" data-orig-file="https://the-gadgeteer.com/wp-content/uploads/2026/09/GoogleBook-OS-9.jpeg" data-orig-size="1440,896" data-comments-opened="1" data-image-title="GoogleBook OS" data-image-description="" data-image-caption="" data-large-file="https://the-gadgeteer.com/wp-content/uploads/2026/09/GoogleBook-OS-9-1280x796.jpeg"></a>
363			</div></figure><figure class="gallery-item">
364			<div class="gallery-icon landscape">
365				<a href="https://the-gadgeteer.com/2026/09/24/5-things-to-love-about-the-new-googlebook-os/screenshot-1651/"><img loading="lazy" decoding="async" width="250" height="250" src="https://the-gadgeteer.com/wp-content/uploads/2026/09/GoogleBook-OS-4-250x250.jpeg" class="attachment-thumbnail size-thumbnail" alt="GoogleBook OS" data-attachment-id="528671" data-permalink="https://the-gadgeteer.com/2026/09/24/5-things-to-love-about-the-new-googlebook-os/screenshot-1651/" data-orig-file="https://the-gadgeteer.com/wp-content/uploads/2026/09/GoogleBook-OS-4.jpeg" data-orig-size="1440,935" data-comments-opened="1" data-image-title="GoogleBook OS" data-image-description="" data-image-caption="" data-large-file="https://the-gadgeteer.com/wp-content/uploads/2026/09/GoogleBook-OS-4-1280x831.jpeg"></a>
366			</div></figure>
367		</div>
368
369<p>That is what makes Googlebook OS interesting. Rather than simply adding another Chromebook-style interface, Google is trying to bring Android, desktop Chrome, Gemini, Linux, and Android phone integration into one laptop platform. For Android users who want their phone and computer to feel like parts of the same ecosystem, it is a compelling start.</p><div class='code-block code-block-11' style='margin: 8px 0; clear: both;'>
370<br>
371<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-8065766046515397"
372     crossorigin="anonymous"></script>
372
373<!-- TGT-ARTICLE-2 -->
374<ins class="adsbygoogle"
375     style="display:block"
376     data-ad-client="ca-pub-8065766046515397"
377     data-ad-slot="9064369787"
378     data-ad-format="auto"
379     data-full-width-responsive="true"></ins>
380<script>
381     (adsbygoogle = window.adsbygoogle || []).push({});
382</script>
382
383<br><br></div>
384
385<div class='code-block code-block-1' style='margin: 8px auto; text-align: center; display: block; clear: both;'>
386<style>
387  .simple-signup-box {
388    background-color: #90D5FF;
389    color: #000;
390    padding: 20px 30px;
391    border-radius: 20px;
392    max-width: 800px;
393    margin: auto;
394    font-family: sans-serif;
395    text-align: left;
396  }
397
398  .simple-signup-box h2 {
399    font-size: 1.4rem;
400    margin: 0 0 6px 0;
401    color: #FFFF00;
402    font-weight: bold;
403  }
404
405  .simple-signup-box p {
406    font-size: 0.9rem;
407    margin: 0 0 12px 0;
408    color: #ccc;
409  }
410
411  .simple-signup-box .signup-button {
412    display: inline-block;
413    padding: 10px 24px;
414    background-color: #0096FF;
415    color: white;
416    border: none;
417    border-radius: 999px;
418    font-size: 0.95rem;
419    font-weight: bold;
420    text-decoration: none;
421    cursor: pointer;
422  }
423</style>
424
425<div class="simple-signup-box">
426<center>
427<strong>Love our content? </strong>
428  <a href="https://newsletter.squintdog.com/subscription?f=NAH947bZNqVX892T763kMynLaDJOdfzaUXqeRdnBuwDZlKHM9p4K0sLCmT7UCI3Hp3763OgjtwGdW9YQ892TqPMXOE5YXw" class="signup-button">Sign up</a> <strong>for our newsletter today.</strong>
429</br></br>
430No ads, no spam, just links to our latest articles!
431  </center>
432</div>
433<br></br></div>
434<div class='code-block code-block-8' style='margin: 8px 0; clear: both;'>
435<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-8065766046515397"
436     crossorigin="anonymous"></script>
436
437<ins class="adsbygoogle"
438     style="display:block"
439     data-ad-format="autorelaxed"
440     data-ad-client="ca-pub-8065766046515397"
441     data-ad-slot="7940550878"></ins>
442<script>
443     (adsbygoogle = window.adsbygoogle || []).push({});
444</script>
444</div>
445<!-- CONTENT END 1 -->
446			</div>
447			<footer class="entry-footer">
448				<nav class="entry-tags" aria-label="Tags"><a class="chip" href="https://the-gadgeteer.com/tag/chromebook/" rel="tag">chromebook</a><a class="chip" href="https://the-gadgeteer.com/tag/computer/" rel="tag">computer</a><a class="chip" href="https://the-gadgeteer.com/tag/google/" rel="tag">Google</a><a class="chip" href="https://the-gadgeteer.com/tag/laptop/" rel="tag">Laptop</a></nav>				<div class="entry-share" id="share"><span class="entry-share__label">Share</span><a class="entry-share__link entry-share__link--twitter" href="https://twitter.com/intent/tweet?text=5%20Reasons%20Googlebook%20OS%20Could%20Be%20Google%E2%80%99s%20Most%20Interesting%20Laptop%20Move%20Yet&#038;url=https%3A%2F%2Fthe-gadgeteer.com%2F2026%2F09%2F24%2F5-things-to-love-about-the-new-googlebook-os%2F" target="_blank" rel="noopener nofollow">Share on X</a><a class="entry-share__link entry-share__link--facebook" href="https://www.facebook.com/sharer/sharer.php?u=https%3A%2F%2Fthe-gadgeteer.com%2F2026%2F09%2F24%2F5-things-to-love-about-the-new-googlebook-os%2F" target="_blank" rel="noopener nofollow">Share on Facebook</a><a class="entry-share__link entry-share__link--pinterest" href="https://pinterest.com/pin/create/button/?url=https%3A%2F%2Fthe-gadgeteer.com%2F2026%2F09%2F24%2F5-things-to-love-about-the-new-googlebook-os%2F&#038;media=https%3A%2F%2Fthe-gadgeteer.com%2Fwp-content%2Fuploads%2F2026%2F09%2FGoogleBook-OS-Cover.jpeg&#038;description=5%20Reasons%20Googlebook%20OS%20Could%20Be%20Google%E2%80%99s%20Most%20Interesting%20Laptop%20Move%20Yet" target="_blank" rel="noopener nofollow">Pin it</a><a class="entry-share__link entry-share__link--email" href="/cdn-cgi/l/email-protection#7c430f091e16191f084149594e4c2e191d0f13120f594e4c3b13131b10191e131317594e4c332f594e4c3f13091018594e4c3e19594e4c3b13131b101959394e59444c5945450f594e4c31130f08594e4c351208190e190f0815121b594e4c301d0c08130c594e4c31130a19594e4c2519085a5f4c4f44471e131805411408080c0f594f3d594e3a594e3a081419511b1d181b190819190e521f1311594e3a4e4c4e4a594e3a4c45594e3a4e48594e3a4951081415121b0f5108135110130a19511d1e130908510814195112190b511b13131b10191e13131751130f594e3a" target="_blank" rel="noopener nofollow">Email</a></div>			</footer>
449				<aside class="author-box" aria-label="About the author">
450		<div class="author-box__avatar"><span class="avatar-initials" aria-hidden="true">RP</span></div>
451		<div class="author-box__body">
452			<div class="author-box__label">About the author</div>
453			<h2 class="author-box__name"><a href="https://the-gadgeteer.com/author/rei/">Rei Padla</a></h2>
454							<p class="author-box__bio"><a href="https://the-gadgeteer.com/author/rei/">More by Rei Padla →</a></p>
455					</div>
456	</aside>
457				<nav class="post-nav" aria-label="Adjacent posts"><a class="post-nav__card post-nav__card--prev" href="https://the-gadgeteer.com/2026/09/24/nikon-z5-iic-no-viewfinder-full-frame-camera/" rel="prev"><span class="post-nav__label">← Previous</span><span class="post-nav__title">The Nikon Z5 IIC Makes Full-Frame Photography Feel More Like a Phone</span></a><a class="post-nav__card post-nav__card--next" href="https://the-gadgeteer.com/2026/09/24/microsoft-surface-mouse-2nd-edition-haptics-action-button/" rel="next"><span class="post-nav__label">Next →</span><span class="post-nav__title">Microsoft&#8217;s New Surface Mouse Adds Haptics to Everyday Clicks</span></a></nav>		</div>
458					<aside class="entry-aside" aria-label="Article extras">
459				<div class="entry-aside__sticky"><nav class="aside-box aside-box--toc" aria-label="In this article"><div class="aside-box__label">In this article</div><ol class="toc"><li><a href="#1-your-android-phone-becomes-part-of-the-laptop-experience">1. Your Android phone becomes part of the laptop experience</a></li><li><a href="#2-magic-pointer-brings-gemini-to-whatever-youre-doing">2. Magic Pointer brings Gemini to whatever you’re doing</a></li><li><a href="#3-android-apps-and-desktop-chrome-share-the-same-foundation">3. Android apps and desktop Chrome share the same foundation</a></li><li><a href="#4-linux-gives-googlebook-os-room-to-do-serious-work">4. Linux gives Googlebook OS room to do serious work</a></li><li><a href="#5-google-is-promising-up-to-10-years-of-updates">5. Google is promising up to 10 years of updates</a></li><li><a href="#who-should-be-excited-about-googlebook-os">Who should be excited about Googlebook OS?</a></li></ol></nav>	<div class="aside-box aside-box--weekly aside-box--dark">
460		<div class="aside-box__label">The Weekly</div>
461		<p class="aside-box__lead">No ads, no spam — just our latest articles.</p>
462		<a class="btn btn--light" href="https://the-gadgeteer.com/subscribe/">Sign up</a>
463	</div>
464	</div>
465							</aside>
466			</div>
467</article>
468<section class="related" aria-label="Latest News"><div class="section-head"><h2 class="section-head__title">Latest News</h2><span class="section-head__rule" aria-hidden="true"></span><a class="section-head__more" href="https://the-gadgeteer.com/category/news/">All News <span aria-hidden="true">→</span></a></div><div class="related__grid related__grid--quad"><article class="card card--news">
469			<div class="card__media">
470							<img width="800" height="533" src="https://the-gadgeteer.com/wp-content/uploads/2026/09/04-structural-color-1-800x533.jpg" class="card__img wp-post-image" alt="04 structural color 1" sizes="auto, (max-width: 520px) 100v
470w, (max-width: 1080px) 50vw, 300px" loading="lazy" decoding="async" srcset="https://the-gadgeteer.com/wp-content/uploads/2026/09/04-structural-color-1-800x533.jpg 800w, https://the-gadgeteer.com/wp-content/uploads/2026/09/04-structural-color-1-1280x853.jpg 1280w, https://the-gadgeteer.com/wp-content/uploads/2026/09/04-structural-color-1-768x512.jpg 768w, https://the-gadgeteer.com/wp-content/uploads/2026/09/04-structural-color-1.jpg 1440w" data-attachment-id="528558" data-permalink="https://the-gadgeteer.com/2026/09/23/casios-platinum-leaf-mr-g-is-a-very-different-kind-of-g-shock-anniversary-watch/04-structural-color-1/" data-orig-file="https://the-gadgeteer.com/wp-content/uploads/2026/09/04-structural-color-1.jpg" data-orig-size="1440,960" data-comments-opened="1" data-image-title="04-structural-color-1" data-image-description="" data-image-caption="" data-large-file="https://the-gadgeteer.com/wp-content/uploads/2026/09/04-structural-color-1-1280x853.jpg">											</div>
471		<div class="card__body">
472		<div class="kicker "><span class="kicker__date">SEP 23</span></div>		<h3 class="card__title"><a class="card__link" href="https://the-gadgeteer.com/2026/09/23/casios-platinum-leaf-mr-g-is-a-very-different-kind-of-g-shock-anniversary-watch/">Casio’s platinum-leaf MR-G is a very different kind of G-SHOCK anniversary watch</a></h3>
473					</div>
474</article>
475<article class="card card--news">
476			<div class="card__media">
477							<img width="800" height="450" src="https://the-gadgeteer.com/wp-content/uploads/2026/09/meta-connect-2026-meta-vr-glasses-lifestyle-closeup-16x9-1440-800x450.jpg" class="card__img wp-post-image" alt="meta connect 2026 meta vr glasses lifestyle closeup 16x9 1440" sizes="auto, (max-width: 520px) 100vw, (max-width: 1080px) 50vw, 300px" loading="lazy" decoding="async" srcset="https://the-gadgeteer.com/wp-content/uploads/2026/09/meta-connect-2026-meta-vr-glasses-lifestyle-closeup-16x9-1440-800x450.jpg 800w, https://the-gadgeteer.com/wp-content/uploads/2026/09/meta-connect-2026-meta-vr-glasses-lifestyle-closeup-16x9-1440-1280x720.jpg 1280w, https://the-gadgeteer.com/wp-content/uploads/2026/09/meta-connect-2026-meta-vr-glasses-lifestyle-closeup-16x9-1440-768x432.jpg 768w, https://the-gadgeteer.com/wp-content/uploads/2026/09/meta-connect-2026-meta-vr-glasses-lifestyle-closeup-16x9-1440.jpg 1440w" data-attachment-id="528531" data-permalink="https://the-gadgeteer.com/2026/09/23/meta-connect-2026-puts-muse-in-your-glasses-and-turns-vr-into-something-you-might-actually-carry/meta-connect-2026-meta-vr-glasses-lifestyle-closeup-16x9-1440/" data-orig-file="https://the-gadgeteer.com/wp-content/uploads/2026/09/meta-connect-2026-meta-vr-glasses-lifestyle-closeup-16x9-1440.jpg" data-orig-size="1440,810" data-comments-opened="1" data-image-title="meta-connect-2026-meta-vr-glasses-lifestyle-closeup-16&amp;#215;9-1440" data-image-description="" data-image-caption="" data-large-file="https://the-gadgeteer.com/wp-content/uploads/2026/09/meta-connect-2026-meta-vr-glasses-lifestyle-closeup-16x9-1440-1280x720.jpg">											</div>
478		<div class="card__body">
479		<div class="kicker "><span class="kicker__date">SEP 23</span></div>		<h3 class="card__title"><a class="card__link" href="https://the-gadgeteer.com/2026/09/23/meta-connect-2026-puts-muse-in-your-glasses-and-turns-vr-into-something-you-might-actually-carry/">Meta Connect 2026 puts Muse in your glasses and turns VR into something you might actually carry</a></h3>
480					</div>
481</article>
482<article class="card card--news">
483			<div class="card__media">
484							<img width="800" height="600" src="https://the-gadgeteer.com/wp-content/uploads/2026/09/inspecs-0-snapdragon-summit-2026-207-800x600.jpg" class="card__img wp-post-image" alt="inspecs 0 snapdragon summit 2026 207" sizes="auto, (max-width: 520px) 100vw, (max-width: 1080px) 50vw, 300px" loading="lazy" decoding="async" srcset="https://the-gadgeteer.com/wp-content/uploads/2026/09/inspecs-0-snapdragon-summit-2026-207-800x600.jpg 800w, https://the-gadgeteer.com/wp-content/uploads/2026/09/inspecs-0-snapdragon-summit-2026-207-768x576.jpg 768w, https://the-gadgeteer.com/wp-content/uploads/2026/09/inspecs-0-snapdragon-summit-2026-207.jpg 1280w" data-attachment-id="528405" data-permalink="https://the-gadgeteer.com/inspecs-0-snapdragon-summit-2026-207/" data-orig-file="https://the-gadgeteer.com/wp-content/uploads/2026/09/inspecs-0-snapdragon-summit-2026-207.jpg" data-orig-size="1280,9
48460" data-comments-opened="1" data-image-title="inspecs-0-snapdragon-summit-2026-207" data-image-description="" data-image-caption="" data-large-file="https://the-gadgeteer.com/wp-content/uploads/2026/09/inspecs-0-snapdragon-summit-2026-207.jpg">											</div>
485		<div class="card__body">
486		<div class="kicker "><span class="kicker__date">SEP 23</span></div>		<h3 class="card__title"><a class="card__link" href="https://the-gadgeteer.com/2026/09/23/inspecs-wants-to-put-hearing-aids-inside-prescription-smart-glasses/">Inspecs wants to put hearing aids inside prescription smart glasses</a></h3>
487					</div>
488</article>
489<article class="card card--news">
490			<div class="card__media">
491							<img width="800" height="600" src="https://the-gadgeteer.com/wp-content/uploads/2026/09/surface-0-snapdragon-summit-2026-surface-laptop-pro-stage-800x600.jpg" class="card__img wp-post-image" alt="surface 0 snapdragon summit 2026 surface laptop pro stage" sizes="auto, (max-width: 520px) 100vw, (max-width: 1080px) 50vw, 300px" loading="lazy" decoding="async" srcset="https://the-gadgeteer.com/wp-content/uploads/2026/09/surface-0-snapdragon-summit-2026-surface-laptop-pro-stage-800x600.jpg 800w, https://the-gadgeteer.com/wp-content/uploads/2026/09/surface-0-snapdragon-summit-2026-surface-laptop-pro-stage-768x576.jpg 768w, https://the-gadgeteer.com/wp-content/uploads/2026/09/surface-0-snapdragon-summit-2026-surface-laptop-pro-stage.jpg 1280w" data-attachment-id="528393" data-permalink="https://the-gadgeteer.com/surface-0-snapdragon-summit-2026-surface-laptop-pro-stage/" data-orig-file="https://the-gadgeteer.com/wp-content/uploads/2026/09/surface-0-snapdragon-summit-2026-surface-laptop-pro-stage.jpg" data-orig-size="1280,960" data-comments-opened="1" data-image-title="surface-0-snapdragon-summit-2026-surface-laptop-pro-stage" data-image-description="" data-image-caption="" data-large-file="https://the-gadgeteer.com/wp-content/uploads/2026/09/surface-0-snapdragon-summit-2026-surface-laptop-pro-stage.jpg">											</div>
492		<div class="card__body">
493		<div class="kicker "><span class="kicker__date">SEP 23</span></div>		<h3 class="card__title"><a class="card__link" href="https://the-gadgeteer.com/2026/09/23/microsofts-compact-surface-pcs-get-snapdragon-x2-plus-and-a-new-pen-workspace/">Microsoft’s compact Surface PCs get Snapdragon X2 Plus and a new pen workspace</a></h3>
494					</div>
495</article>
496</div></section><div id="comments" class="comments-area">
497	
498		<div id="respond" class="comment-respond">
499		<h2 id="reply-title" class="comment-reply-title">Leave a Reply <small><a rel="nofollow" id="cancel-comment-reply-link" href="/2026/09/24/5-things-to-love-about-the-new-googlebook-os/#respond" style="display:none;">Cancel reply</a></small></h2><form action="https://the-gadgeteer.com/wp-comments-post.php" method="post" id="commentform" class="comment-form"><p class="comment-notes"><span id="email-notes">Your email address will not be published.</span> <span class="required-field-message">Required fields are marked <span class="required">*</span></span></p><p class="comment-form-comment"><label for="comment">Comment <span class="required">*</span></label> <textarea autocomplete="new-password"  id="h4829477e0"  name="h4829477e0"   cols="45" rows="8" maxlength="65525" required></textarea><textarea id="comment" aria-label="hp-comment" aria-hidden="true" name="comment" autocomplete="new-password" style="padding:0 !important;clip:rect(1px, 1px, 1px, 1px) !important;position:absolute !important;white-space:nowrap !important;height:1px !important;width:1px !important;overflow:hidden !important;" tabindex="-1"></textarea>
vendor: 108 bytes, line 499
499<script data-cfasync="false" src="/cdn-cgi/scripts/5c5dd728/cloudflare-static/email-decode.min.js"></script>
499<script data-noptimize>document.getElementById("comment").setAttribute( "id", "aec789b7331bdea395a41654270799b6" );document.getElementById("h4829477e0").setAttribute( "id", "comment" );</script>
499</p><p class="comment-form-author"><label for="author">Name <span class="required">*</span></label> <input id="author" name="author" type="text" value="" size="30" maxlength="245" autocomplete="name" required /></p>
500<p class="comment-form-email"><label for="email">Email <span class="required">*</span></label> <input id="email" name="email" type="email" value="" size="30" maxlength="100" aria-describedby="email-notes" autocomplete="email" required /></p>
501<p class="comment-form-url"><label for="url">Website</label> <input id="url" name="url" type="url" value="" size="30" maxlength="200" autocomplete="url" /></p>
502		<input
503				type="hidden"
504				class="hcaptcha-widget-id"
505				name="hcaptcha-widget-id"
506				value="eyJzb3VyY2UiOlsiV29yZFByZXNzIl0sImZvcm1faWQiOjUyODY2M30=-f441d65b3c78c247432a09efd515b2c7">
507				<input
508				type="hidden"
509				class="hcaptcha-signature"
510				name="hcaptcha-signature-SENhcHRjaGFcV1BcQ29tbWVudA=="
511				value="eyJzb3VyY2UiOlsiV29yZFByZXNzIl0sImZvcm1faWQiOjUyODY2MywiaGNhcHRjaGFfc2hvd24iOnRydWV9-f9b9a8485f826f85c8aced7af30002e1">
512				<h-captcha
513			class="h-captcha"
514			data-sitekey="bd2e4bf8-be36-4c34-9c42-1890bbfa8a0e"
515			data-theme="light"
516			data-size="normal"
517			data-auto="false"
518			data-ajax="false"
519			data-force="false">
520		</h-captcha>
521		<input type="hidden" id="hcaptcha_comment_nonce" name="hcaptcha_comment_nonce" value="e55797f9ea" /><input type="hidden" name="_wp_http_referer" value="/2026/09/24/5-things-to-love-about-the-new-googlebook-os/" /><p class='comment-form-subscriptions'><label for='subscribe-reloaded'><select name='subscribe-reloaded' id='subscribe-reloaded'>
522								<option value='none' >Don&#039;t subscribe</option>
523								<option value='yes' >All new comments</option>
524								<option value='replies' selected='selected'>Replies to my comments</option>
525							</select> Notify me of followup comments via e-mail. You can also <a href="https://the-gadgeteer.com/comment-subscriptions/?srp=528663&amp;srk=ac6d22e265055dcc48478983c2e14eb8&amp;sra=s&amp;srsrc=f">subscribe</a> without commenting.</label></p><p class="form-submit"><input name="submit" type="submit" id="submit" class="submit button" value="Post Comment" /> <input type='hidden' name='comment_post_ID' value='528663' id='comment_post_ID' />
526<input type='hidden' name='comment_parent' id='comment_parent' value='0' />
527</p></form>	</div><!-- #respond -->
528	</div>
529</main>
530	</div><!-- #content -->
531
532	<footer id="colophon" class="site-footer">
533		<div class="site-footer__grid">
534			<div class="site-footer__brand">
535				<a class="site-footer__wordmark" href="https://the-gadgeteer.com/" rel="home">The Gadgeteer</a>
536									<div class="site-footer__tagline">Gadget news and reviews since 1997</div>
537							</div>
538							<nav class="site-footer__nav" aria-label="Sections">
539					<ul id="menu-main-menu" class="footer-links"><li class="menuheader menu-item menu-item-type-custom menu-item-object-custom menu-item-220961"><a href="https://the-gadgeteer.com/category/reviews/">Reviews</a></li>
540<li class="menu-item menu-item-type-custom menu-item-object-custom menu-item-233577"><a>Articles</a></li>
541<li class="menu-item menu-item-type-taxonomy menu-item-object-post_tag menu-item-382634 menu-item-signal"><a href="https://the-gadgeteer.com/category/deals/">Deals</a></li>
542<li class="menu-item menu-item-type-taxonomy menu-item-object-category menu-item-495790"><a href="https://the-gadgeteer.com/category/buyers-guide/">Buyer&#8217;s Guide</a></li>
543<li class="menuheader menu-item menu-item-type-taxonomy menu-item-object-post_tag menu-item-217896 menu-item-extra"><a href="https://the-gadgeteer.com/tag/edc/">EDC</a></li>
544</ul>				</nav>
545										<nav class="site-footer__nav" aria-label="About">
546					<ul id="menu-footer-menu" class="footer-links"><li id="menu-item-205903" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-205903"><a href="https://the-gadgeteer.com/about/">About</a></li>
547<li id="menu-item-205904" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-205904"><a href="https://the-gadgeteer.com/subscribe/">Follow Us!</a></li>
548<li id="menu-item-205902" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-205902"><a href="https://the-gadgeteer.com/contact/">Contact us</a></li>
549<li id="menu-item-231374" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-privacy-policy menu-item-231374"><a rel="privacy-policy" href="https://the-gadgeteer.com/privacy/">Privacy Policy</a></li>
550<li id="menu-item-241362" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-241362"><a href="https://the-gadgeteer.com/terms-of-service/">Terms of Service</a></li>
551<li id="menu-item-231375" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-231375"><a href="https://the-gadgeteer.com/disclosure/">Disclosure</a></li>
552<li id="menu-item-324127" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-324127"><a href="https://the-gadgeteer.com/the-gadgeteer-com-website-accessibly-statement/">Accessibly Statement</a></li>
553</ul>				</nav>
554						<div class="site-footer__follow">
555				<nav aria-label="Follow"><ul class="footer-links footer-links--follow"><li><a class="footer-links__newsletter" href="https://the-gadgeteer.com/subscribe/">Newsletter</a></li><li><a class="footer-links__rss" href="https://the-gadgeteer.com/feed/">RSS</a></li><li><a class="footer-links__google_news" href="https://news.google.com/publications/CAAqLQgKIidDQklTRndnTWFoTUtFWFJvWlMxbllXUm5aWFJsWlhJdVkyOXRLQUFQAQ?hl=en-US&#038;gl=US&#038;ceid=US%3Aen" target="_blank" rel="noopener">Google News</a></li><li><a class="footer-links__youtube" href="https://www.youtube.com/@the-gadgeteer" target="_blank" rel="noopener">YouTube</a></li></ul></nav>			</div>
556		</div>
557		<div class="site-footer__legal">
558			<p>© 2026 The Gadgeteer · All rights reserved</p>
559		</div>
560	</footer>
561</div><!-- #page -->
562
563<script type="speculationrules">
564{"prefetch":[{"source":"document","where":{"and":[{"href_matches":"/*"},{"not":{"href_matches":["/wp-*.php","/wp-admin/*","/wp-content/uploads/*","/wp-content/*","/wp-content/plugins/*","/wp-content/themes/gadgeteer/*","/*\\?(.+)"]}},{"not":{"selector_matches":"a[rel~=\"nofollow\"]"}},{"not":{"selector_matches":".no-prefetch, .no-prefetch a"}}]},"eagerness":"conservative"}]}
565</script>
565
566		<div id="jp-carousel-loading-overlay" style="display: none;">
567			<div id="jp-carousel-loading-wrapper">
568				<span id="jp-carousel-library-loading"><svg class="jetpack-spinner" width="40" height="40" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><circle cx="50" cy="50" r="46" fill="none" stroke="#ddd" stroke-width="8"/><path d="M 50 4 A 46 46 0 0 1 96 50" fill="none" stroke="currentColor" stroke-width="8" stroke-linecap="round"><animateTransform attributeName="transform" type="rotate" dur="1.4s" from="0 50 50" to="360 50 50" repeatCount="indefinite"/></path></svg></span>
569			</div>
570		</div>
571		<div class="jp-carousel-overlay" style="display: none;">
572
573		<div class="jp-carousel-container">
574			<!-- The Carousel Swiper -->
575			<div
576				class="jp-carousel-wrap swiper jp-carousel-swiper-container jp-carousel-transitions"
577				itemscope
578				itemtype="https://schema.org/ImageGallery">
579				<div class="jp-carousel swiper-wrapper"></div>
580				<div class="jp-swiper-button-prev swiper-button-prev">
581					<svg width="25" height="24" viewBox="0 0 25 24" fill="none" xmlns="http://www.w3.org/2000/svg">
582						<mask id="maskPrev" mask-type="alpha" maskUnits="userSpaceOnUse" x="8" y="6" width="9" height="12">
583							<path d="M16.2072 16.59L11.6496 12L16.2072 7.41L14.8041 6L8.8335 12L14.8041 18L16.2072 16.59Z" fill="white"/>
584						</mask>
585						<g mask="url(#maskPrev)">
586							<rect x="0.579102" width="23.8823" height="24" fill="#FFFFFF"/>
587						</g>
588					</svg>
589				</div>
590				<div class="jp-swiper-button-next swiper-button-next">
591					<svg width="25" height="24" viewBox="0 0 25 24" fill="none" xmlns="http://www.w3.org/2000/svg">
592						<mask id="maskNext" mask-type="alpha" maskUnits="userSpaceOnUse" x="8" y="6" width="8" height="12">
593							<path d="M8.59814 16.59L13.1557 12L8.59814 7.41L10.0012 6L15.9718 12L10.0012 18L8.59814 16.59Z" fill="white"/>
594						</mask>
595						<g mask="url(#maskNext)">
596							<rect x="0.34375" width="23.8822" height="24" fill="#FFFFFF"/>
597						</g>
598					</svg>
599				</div>
600			</div>
601			<!-- The main close buton -->
602			<div class="jp-carousel-close-hint">
603				<svg width="25" height="24" viewBox="0 0 25 24" fill="none" xmlns="http://www.w3.org/2000/svg">
604					<mask id="maskClose" mask-type="alpha" maskUnits="userSpaceOnUse" x="5" y="5" width="15" height="14">
605						<path d="M19.3166 6.41L17.9135 5L12.3509 10.59L6.78834 5L5.38525 6.41L10.9478 12L5.38525 17.59L6.78834 19L12.3509 13.41L17.9135 19L19.3166 17.59L13.754 12L19.3166 6.41Z" fill="white"/>
606					</mask>
607					<g mask="url(#maskClose)">
608						<rect x="0.409668" width="23.8823" height="24" fill="#FFFFFF"/>
609					</g>
610				</svg>
611			</div>
612			<!-- Image info, comments and meta -->
613			<div class="jp-carousel-info">
614				<div class="jp-carousel-info-footer">
615					<div class="jp-carousel-pagination-container">
616						<div class="jp-swiper-pagination swiper-pagination"></div>
617						<div class="jp-carousel-pagination"></div>
618					</div>
619					<div class="jp-carousel-photo-title-container">
620						<div class="jp-carousel-photo-caption"></div>
621					</div>
622					<div class="jp-carousel-photo-icons-container">
623						<a href="#" class="jp-carousel-icon-btn jp-carousel-icon-info" aria-label="Toggle photo metadata visibility">
624							<span class="jp-carousel-icon">
625								<svg width="25" height="24" viewBox="0 0 25 24" fill="none" xmlns="http://www.w3.org/2000/svg">
626									<mask id="maskInfo" mask-type="alpha" maskUnits="userSpaceOnUse" x="2" y="2" width="21" height="20">
627										<path fill-rule="evenodd" clip-rule="evenodd" d="M12.7537 2C7.26076 2 2.80273 6.48 2.80273 12C2.80273 17.52 7.26076 22 12.7537 22C18.2466 22 22.7046 17.52 22.7046 12C22.7046 6.48 18.2466 2 12.7537 2ZM11.7586 7V9H13.7488V7H11.7586ZM11.7586 11V17H13.7488V11H11.7586ZM4.79292 12C4.79292 16.41 8.36531 20 12.7537 20C17.142 20 20.7144 16.41 20.7144 12C20.7144 7.59 17.142 4 12.7537 4C8.36531 4 4.79292 7.59 4.79292 12Z" fill="white"/>
628									</mask>
629									<g mask="url(#maskInfo)">
630										<rect x="0.8125" width="23.8823" height="24" fill="#FFFFFF"/>
631									</g>
632								</svg>
633							</span>
634						</a>
635											</div>
636				</div>
637				<div class="jp-carousel-info-extra">
638					<div class="jp-carousel-info-content-wrapper">
639						<div class="jp-carousel-photo-title-container">
640							<div class="jp-carousel-photo-title"></div>
641						</div>
642						<div class="jp-carousel-comments-wrapper">
643													</div>
644						<div class="jp-carousel-image-meta">
645							<div class="jp-carousel-title-and-caption">
646								<div class="jp-carousel-photo-info">
647									<div class="jp-carousel-caption" itemprop="caption description"></div>
648								</div>
649
650								<div class="jp-carousel-photo-description"></div>
651							</div>
652							<a class="jp-carousel-image-download" href="#" aria-label="Download image" target="_blank" style="display: none;">
653								<svg width="25" height="24" viewBox="0 0 25 24" fill="none" xmlns="http://www.w3.org/2000/svg">
654									<mask id="mask0" mask-type="alpha" maskUnits="userSpaceOnUse" x="3" y="3" width="19" height="18">
655										<path fill-rule="evenodd" clip-rule="evenodd" d="M5.84615 5V19H19.7775V12H21.7677V19C21.7677 20.1 20.8721 21 19.7775 21H5.84615C4.74159 21 3.85596 20.1 3.85596 19V5C3.85596 3.9 4.74159 3 5.84615 3H12.8118V5H5.84615ZM14.802 5V3H21.7677V10H19.7775V6.41L9.99569 16.24L8.59261 14.83L18.3744 5H14.802Z" fill="white"/>
656									</mask>
657									<g mask="url(#mask0)">
658										<rect x="0.870605" width="23.8823" height="24" fill="#FFFFFF"/>
659									</g>
660								</svg>
661								<span class="jp-carousel-download-text"></span>
662							</a>
663							<div class="jp-carousel-image-map" style="display: none;"></div>
664						</div>
665					</div>
666				</div>
667			</div>
668		</div>
669
670		</div>
671		
671<script>
672var HCaptchaMainObject = {"params":"{\"sitekey\":\"bd2e4bf8-be36-4c34-9c42-1890bbfa8a0e\",\"theme\":\"light\",\"size\":\"normal\",\"hl\":\"en\"}"};
673</script>
vendor: 1 bytes, line 673
673
674<script>
675(()=>{'use strict';let loaded=!1,scrolled=!1,timerId;function load(){if(loaded){return}
676loaded=!0;clearTimeout(timerId);window.removeEventListener('touchstart',load);document.body.removeEventListener('mouseenter',load);document.body.removeEventListener('click',load);window.removeEventListener('keydown',load);window.removeEventListener('scroll',scrollHandler);const t=document.getElementsByTagName('script')[0];const s=document.createElement('script');s.type='text/javascript';s.id='hcaptcha-api';s.src='https://js.hcaptcha.com/1/api.js?onload=hCaptchaOnLoad&render=explicit';s.async=!0;t.parentNode.insertBefore(s,t)}
677function scrollHandler(){if(!scrolled){scrolled=!0;return}
678load()}
679document.addEventListener('hCaptchaBeforeAPI',function(){const delay=-100;if(delay>=0){timerId=setTimeout(load,delay)}
680const options={passive:!0};window.addEventListener('touchstart',load,options);document.body.addEventListener('mouseenter',load);document.body.addEventListener('click',load);window.addEventListener('keydown',load);window.addEventListener('scroll',scrollHandler,options)})})()
681</script>
vendor: 1 bytes, line 681
681
682<script id="wp-hooks-js" src="https://the-gadgeteer.com/wp-includes/js/dist/hooks.min.js?ver=f0f188028580e8dc1255"></script>
vendor: 1 bytes, line 682
682
683<script id="wp-i18n-js" src="https://the-gadgeteer.com/wp-includes/js/dist/i18n.min.js?ver=1dfe7db3940c23ea9216"></script>
vendor: 1 bytes, line 683
683
684<script id="wp-i18n-js-after">
685wp.i18n.setLocaleData( { 'text direction\u0004ltr': [ 'ltr' ] } );
686//# sourceURL=wp-i18n-js-after
687</script>
vendor: 1 bytes, line 687
687
688<script id="swv-js" src="https://the-gadgeteer.com/wp-content/plugins/contact-form-7/includes/swv/js/index.js?ver=6.1.7"></script>
vendor: 1 bytes, line 688
688
689<script id="contact-form-7-js-before">
690var wpcf7 = {
691    "api": {
692        "root": "https:\/\/the-gadgeteer.com\/wp-json\/",
693        "namespace": "contact-form-7\/v1"
694    },
695    "cached": 1
696};
697//# sourceURL=contact-form-7-js-before
698</script>
vendor: 1 bytes, line 698
698
699<script id="contact-form-7-js" src="https://the-gadgeteer.com/wp-content/plugins/contact-form-7/includes/js/index.js?ver=6.1.7"></script>
vendor: 1 bytes, line 699
699
700<script data-wp-strategy="defer" defer id="gadgeteer-js" src="https://the-gadgeteer.com/wp-content/themes/gadgeteer/assets/js/gadgeteer.js?ver=1790225310"></script>
vendor: 1 bytes, line 700
700
701<script async data-wp-strategy="async" fetchpriority="low" id="comment-reply-js" src="https://the-gadgeteer.com/wp-includes/js/comment-reply.min.js?ver=7.1.2"></script>
vendor: 1 bytes, line 701
701
702<script id="jetpack-stats-js-before">
703_stq = window._stq || [];
704_stq.push([ "view", {"v":"ext","blog":"55735439","post":"528663","tz":"-5","srv":"the-gadgeteer.com","j":"1:16.2"} ]);
705_stq.push([ "clickTrackerInit", "55735439", "528663" ]);
706//# sourceURL=jetpack-stats-js-before
707</script>
vendor: 1 bytes, line 707
707
708<script data-wp-strategy="defer" defer fetchpriority="low" id="jetpack-stats-js" src="https://stats.wp.com/e-202639.js"></script>
vendor: 1 bytes, line 708
708
709<script id="jetpack-carousel-js-extra">
710var jetpackSwiperLibraryPath = {"url":"https://the-gadgeteer.com/wp-content/plugins/jetpack/_inc/blocks/swiper.js"};
711var jetpackCarouselStrings = {"widths":[370,700,1000,1200,1400,2000],"is_logged_in":"","lang":"en","ajaxurl":"https://the-gadgeteer.com/wp-admin/admin-ajax.php","nonce":"0832d5f0c2","display_exif":"0","display_comments":"0","single_image_gallery":"1","single_image_gallery_media_file":"","background_color":"black","comment":"Comment","post_comment":"Post Comment","write_comment":"Write a Comment...","loading_comments":"Loading Comments...","image_label":"Open image in full-screen.","download_original":"View full size \u003Cspan class=\"photo-size\"\u003E{0}\u003Cspan class=\"photo-size-times\"\u003E\u00d7\u003C/span\u003E{1}\u003C/span\u003E","no_comment_text":"Please be sure to submit some text with your comment.","no_comment_email":"Please provide an email address to comment.","no_comment_author":"Please provide your name to comment.","comment_post_error":"Sorry, but there was an error posting your comment. Please try again later.","comment_approved":"Your comment was approved.","comment_unapproved":"Your comment is in moderation.","camera":"Camera","aperture":"Aperture","shutter_speed":"Shutter Speed","focal_length":"Focal Length","copyright":"Copyright","comment_registration":"0","require_name_email":"1","login_url":"https://the-gadgeteer.com/wp-login.php?redirect_to=https%3A%2F%2Fthe-gadgeteer.com%2F2026%2F09%2F24%2F5-things-to-love-about-the-new-googlebook-os%2F","blog_id":"1","meta_data":["camera","aperture","shutter_speed","focal_length","copyright"]};
712//# sourceURL=jetpack-carousel-js-extra
713</script>
vendor: 1 bytes, line 713
713
714<script id="jetpack-carousel-js" src="https://the-gadgeteer.com/wp-content/plugins/jetpack/_inc/build/carousel/jetpack-carousel.min.js?ver=16.2"></script>
vendor: 1 bytes, line 714
714
715<script id="hcaptcha-js" src="https://the-gadgeteer.com/wp-content/plugins/hcaptcha-for-forms-and-more/assets/js/apps/hcaptcha.js?ver=5.3.0"></script>
715
716
717<!-- Gadgeteer: site footer scripts -->
718<!-- Clicky: JavaScript-disabled fallback -->
719<noscript><p><img alt="Clicky" width="1" height="1" src="//in.getclicky.com/101496649ns.gif" /></p></noscript>
720<script>
721ai_adb_fe_dbg = true;ai_debugging = true;
722function b2a (a) {
723  var c, d, e, f, g, h, i, j, o, b = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=", k = 0, l = 0, m = "", n = [];
724  if (!a) return a;
725  do c = a.charCodeAt(k++), d = a.charCodeAt(k++), e = a.charCodeAt(k++), j = c << 16 | d << 8 | e,
726  f = 63 & j >> 18, g = 63 & j >> 12, h = 63 & j >> 6, i = 63 & j, n[l++] = b.charAt(f) + b.charAt(g) + b.charAt(h) + b.charAt(i); while (k < a.length);
727  return m = n.join(""), o = a.length % 3, (o ? m.slice(0, o - 3) :m) + "===".slice(o || 3);
728}
729
730function a2b (a) {
731  var b, c, d, e = {}, f = 0, g = 0, h = "", i = String.fromCharCode, j = a.length;
732  for (b = 0; 64 > b; b++) e["ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".charAt(b)] = b;
733  for (c = 0; j > c; c++) for (b = e[a.charAt(c)], f = (f << 6) + b, g += 6; g >= 8; ) ((d = 255 & f >>> (g -= 8)) || j - 2 > c) && (h += i(d));
734  return h;
735}
736
737b64e = function (str) {
738  return btoa (encodeURIComponent (str).replace (/%([0-9A-F]{2})/g,
739    function toSolidBytes (match, p1) {
740      return String.fromCharCode ('0x' + p1);
741  }));
742}
743
744b64d = function (str) {
745  return decodeURIComponent (atob (str).split ('').map (function(c) {
746    return '%' + ('00' + c.charCodeAt (0).toString (16)).slice (-2);
747  }).join (''));
748}
749/* <![CDATA[ */
750ai_front = {"insertion_before":"BEFORE","insertion_after":"AFTER","insertion_prepend":"PREPEND CONTENT","insertion_append":"APPEND CONTENT","insertion_replace_content":"REPLACE CONTENT","insertion_replace_element":"REPLACE ELEMENT","visible":"VISIBLE","hidden":"HIDDEN","fallback":"FALLBACK","automatically_placed":"Automatically placed by AdSense Auto ads code","cancel":"Cancel","use":"Use","add":"Add","parent":"Parent","cancel_element_selection":"Cancel element selection","select_parent_element":"Select parent element","css_selector":"CSS selector","use_current_selector":"Use current selector","element":"ELEMENT","path":"PATH","selector":"SELECTOR"};
751/* ]]> */
752var ai_cookie_js = true;
753var ai_block_class_def = 'code-block';
754
755if (typeof ai_cookie_js !== 'undefined') {
756
757/*! js-cookie v3.0.5 | MIT */
758;
759(function (global, factory) {
760  typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
761  typeof define === 'function' && define.amd ? define(factory) :
762  (global = typeof globalThis !== 'undefined' ? globalThis : global || self, (function () {
763    var current = global.Cookies;
764    var exports = global.Cookies = factory();
765    exports.noConflict = function () { global.Cookies = current; return exports; };
766  })());
767})(this, (function () { 'use strict';
768
769  /* eslint-disable no-var */
770  function assign (target) {
771    for (var i = 1; i < arguments.length; i++) {
772      var source = arguments[i];
773      for (var key in source) {
774        target[key] = source[key];
775      }
776    }
777    return target
778  }
779  /* eslint-enable no-var */
780
781  /* eslint-disable no-var */
782  var defaultConverter = {
783    read: function (value) {
784      if (value[0] === '"') {
785        value = value.slice(1, -1);
786      }
787      return value.replace(/(%[\dA-F]{2})+/gi, decodeURIComponent)
788    },
789    write: function (value) {
790      return encodeURIComponent(value).replace(
791        /%(2[346BF]|3[AC-F]|40|5[BDE]|60|7[BCD])/g,
792        decodeURIComponent
793      )
794    }
795  };
796  /* eslint-enable no-var */
797
798  /* eslint-disable no-var */
799
800  function init (converter, defaultAttributes) {
801    function set (name, value, attributes) {
802      if (typeof document === 'undefined') {
803        return
804      }
805
806      attributes = assign({}, defaultAttributes, attributes);
807
808      if (typeof attributes.expires === 'number') {
809        attributes.expires = new Date(Date.now() + attributes.expires * 864e5);
810      }
811      if (attributes.expires) {
812        attributes.expires = attributes.expires.toUTCString();
813      }
814
815      name = encodeURIComponent(name)
816        .replace(/%(2[346B]|5E|60|7C)/g, decodeURIComponent)
817        .replace(/[()]/g, escape);
818
819      var stringifiedAttributes = '';
820      for (var attributeName in attributes) {
821        if (!attributes[attributeName]) {
822          continue
823        }
824
vendor: 4,592 bytes, lines 825-988
825        stringifiedAttributes += '; ' + attributeName;
826
827        if (attributes[attributeName] === true) {
828          continue
829        }
830
831        // Considers RFC 6265 section 5.2:
832        // ...
833        // 3.  If the remaining unparsed-attributes contains a %x3B (";")
834        //     character:
835        // Consume the characters of the unparsed-attributes up to,
836        // not including, the first %x3B (";") character.
837        // ...
838        stringifiedAttributes += '=' + attributes[attributeName].split(';')[0];
839      }
840
841      return (document.cookie =
842        name + '=' + converter.write(value, name) + stringifiedAttributes)
843    }
844
845    function get (name) {
846      if (typeof document === 'undefined' || (arguments.length && !name)) {
847        return
848      }
849
850      // To prevent the for loop in the first place assign an empty array
851      // in case there are no cookies at all.
852      var cookies = document.cookie ? document.cookie.split('; ') : [];
853      var jar = {};
854      for (var i = 0; i < cookies.length; i++) {
855        var parts = cookies[i].split('=');
856        var value = parts.slice(1).join('=');
857
858        try {
859          var found = decodeURIComponent(parts[0]);
860          jar[found] = converter.read(value, found);
861
862          if (name === found) {
863            break
864          }
865        } catch (e) {}
866      }
867
868      return name ? jar[name] : jar
869    }
870
871    return Object.create(
872      {
873        set,
874        get,
875        remove: function (name, attributes) {
876          set(
877            name,
878            '',
879            assign({}, attributes, {
880              expires: -1
881            })
882          );
883        },
884        withAttributes: function (attributes) {
885          return init(this.converter, assign({}, this.attributes, attributes))
886        },
887        withConverter: function (converter) {
888          return init(assign({}, this.converter, converter), this.attributes)
889        }
890      },
891      {
892        attributes: { value: Object.freeze(defaultAttributes) },
893        converter: { value: Object.freeze(converter) }
894      }
895    )
896  }
897
898  var api = init(defaultConverter, { path: '/' });
899  /* eslint-enable no-var */
900
901  return api;
902
903}));
904
905/*!
906 * JavaScript Cookie v2.2.0
907 * https://github.com/js-cookie/js-cookie
908 *
909 * Copyright 2006, 2015 Klaus Hartl & Fagner Brack
910 * Released under the MIT license
911 */
912/*
913;(function (factory) {
914  var registeredInModuleLoader;
915  if (typeof define === 'function' && define.amd) {
916    define(factory);
917    registeredInModuleLoader = true;
918  }
919  if (typeof exports === 'object') {
920    module.exports = factory();
921    registeredInModuleLoader = true;
922  }
923  if (!registeredInModuleLoader) {
924    var OldCookies = window.Cookies;
925    var api = window.Cookies = factory();
926    api.noConflict = function () {
927      window.Cookies = OldCookies;
928      return api;
929    };
930  }
931}(function () {
932  function extend () {
933    var i = 0;
934    var result = {};
935    for (; i < arguments.length; i++) {
936      var attributes = arguments[ i ];
937      for (var key in attributes) {
938        result[key] = attributes[key];
939      }
940    }
941    return result;
942  }
943
944  function decode (s) {
945    return s.replace(/(%[0-9A-Z]{2})+/g, decodeURIComponent);
946  }
947
948  function init (converter) {
949    function api() {}
950
951    function set (key, value, attributes) {
952      if (typeof document === 'undefined') {
953        return;
954      }
955
956      attributes = extend({
957        path: '/',
958        sameSite: 'Lax'
959      }, api.defaults, attributes);
960
961      if (typeof attributes.expires === 'number') {
962        attributes.expires = new Date(new Date() * 1 + attributes.expires * 864e+5);
963      }
964
965      // We're using "expires" because "max-age" is not supported by IE
966      attributes.expires = attributes.expires ? attributes.expires.toUTCString() : '';
967
968      try {
969        var result = JSON.stringify(value);
970        if (/^[\{\[]/.test(result)) {
971          value = result;
972        }
973      } catch (e) {}
974
975      value = converter.write ?
976        converter.write(value, key) :
977        encodeURIComponent(String(value))
978          .replace(/%(23|24|26|2B|3A|3C|3E|3D|2F|3F|40|5B|5D|5E|60|7B|7D|7C)/g, decodeURIComponent);
979
980      key = encodeURIComponent(String(key))
981        .replace(/%(23|24|26|2B|5E|60|7C)/g, decodeURIComponent)
982        .replace(/[\(\)]/g, escape);
983
984      var stringifiedAttributes = '';
985      for (var attributeName in attributes) {
986        if (!attributes[attributeName]) {
987          continue;
988        }
989        stringifiedAttributes += '; ' + attributeName;
990        if (attributes[attributeName] === true) {
991          continue;
992        }
993
994        // Considers RFC 6265 section 5.2:
995        // ...
996        // 3.  If the remaining unparsed-attributes contains a %x3B (";")
997        //     character:
998        // Consume the characters of the unparsed-attributes up to,
999        // not including, the first %x3B (";") character.
1000        // ...
1001        stringifiedAttributes += '=' + attributes[attributeName].split(';')[0];
1002      }
1003
1004      return (document.cookie = key + '=' + value + stringifiedAttributes);
1005    }
1006
1007    function get (key, json) {
1008      if (typeof document === 'undefined') {
1009        return;
1010      }
1011
1012      var jar = {};
1013      // To prevent the for loop in the first place assign an empty array
1014      // in case there are no cookies at all.
1015      var cookies = document.cookie ? document.cookie.split('; ') : [];
1016      var i = 0;
1017
1018      for (; i < cookies.length; i++) {
1019        var parts = cookies[i].split('=');
1020        var cookie = parts.slice(1).join('=');
1021
1022        if (!json && cookie.charAt(0) === '"') {
1023          cookie = cookie.slice(1, -1);
1024        }
1025
1026        try {
1027          var name = decode(parts[0]);
1028          cookie = (converter.read || converter)(cookie, name) ||
1029            decode(cookie);
1030
1031          if (json) {
1032            try {
1033              cookie = JSON.parse(cookie);
1034            } catch (e) {}
1035          }
1036
1037          jar[name] = cookie;
1038
1039          if (key === name) {
1040            break;
1041          }
1042        } catch (e) {}
1043      }
1044
1045      return key ? jar[key] : jar;
1046    }
1047
1048    api.set = set;
1049    api.get = function (key) {
1050      return get(key, false /* read as raw * /);
1051    };
1052    api.getJSON = function (key) {
1053      return get(key, true /* read as json * /);
1054    };
1055    api.remove = function (key, attributes) {
1056      set(key, '', extend(attributes, {
1057        expires: -1
1058      }));
1059    };
1060
1061    api.defaults = {};
1062
1063    api.withConverter = init;
1064
1065    return api;
1066  }
1067
1068  return init(function () {});
1069}));
1070*/
1071
1072AiCookies = Cookies.noConflict();
1073
1074
1075function ai_json_data (cookie) {
1076  if (cookie == null) {
1077    return cookie;
1078  }
1079
1080  if (cookie.charAt (0) === '"') {
1081    cookie = cookie.slice (1, -1);
1082  }
1083
1084  try {
1085    cookie = JSON.parse (cookie);
1086  } catch (e) {}
1087
1088  return cookie;
1089}
1090
1091ai_check_block = function (block) {
1092//  var ai_debug = typeof ai_debugging !== 'undefined'; // 1
1093  var ai_debug = false;
1094
1095  if (block == null) {
1096    return true;
1097  }
1098
1099  var ai_cookie_name = 'aiBLOCKS';
1100//  ###
1101//  var ai_cookie = AiCookies.getJSON (ai_cookie_name);
1102  var ai_cookie = ai_json_data (AiCookies.get (ai_cookie_name));
1103
1104  ai_debug_cookie_status = '';
1105
1106  if (ai_cookie == null) {
1107    ai_cookie = {};
1108  }
1109
1110  if (typeof ai_delay_showing_pageviews !== 'undefined') {
1111    if (!ai_cookie.hasOwnProperty (block)) {
1112      ai_cookie [block] = {};
1113    }
1114
1115    if (!ai_cookie [block].hasOwnProperty ('d')) {
1116      ai_cookie [block]['d'] = ai_delay_showing_pageviews;
1117
1118      if (ai_debug) console.log ('AI CHECK block', block, 'NO COOKIE DATA d, delayed for', ai_delay_showing_pageviews, 'pageviews');
1119    }
1120  }
1121
1122  if (ai_cookie.hasOwnProperty (block)) {
1123    for (var cookie_block_property in ai_cookie [block]) {
1124
1125      if (cookie_block_property == 'x') {
1126
1127        var code_hash = '';
1128        var block_object = document.querySelectorAll ('span[data-ai-block="'+block+'"]') [0]
1129        if ("aiHash" in block_object.dataset) {
1130          code_hash = block_object.dataset.aiHash;
1131        }
1132
1133        var cookie_code_hash = '';
1134        if (ai_cookie [block].hasOwnProperty ('h')) {
1135          cookie_code_hash = ai_cookie [block]['h'];
1136        }
1137        if (ai_debug) console.log ('AI CHECK block', block, 'x cookie hash', cookie_code_hash, 'code hash', code_hash);
1138
1139        var date = new Date();
1140        var closed_for = ai_cookie [block][cookie_block_property] - Math.round (date.getTime() / 1000);
1141        if (closed_for > 0 && cookie_code_hash == code_hash) {
1142          var message = 'closed for ' + closed_for + ' s = ' + (Math.round (10000 * closed_for / 3600 / 24) / 10000) + ' days';
1143          ai_debug_cookie_status = message;
1144          if (ai_debug) console.log ('AI CHECK block', block, message);
1145          if (ai_debug) console.log ('');
1146
1147          return false;
1148        } else {
1149            if (ai_debug) console.log ('AI CHECK block', block, 'removing x');
1150
1151            ai_set_cookie (block, 'x', '');
1152            if (!ai_cookie [block].hasOwnProperty ('i') && !ai_cookie [block].hasOwnProperty ('c')) {
1153              ai_set_cookie (block, 'h', '');
1154            }
1155          }
1156      } else
1157      if (cookie_block_property == 'd') {
1158        if (ai_cookie [block][cookie_block_property] != 0) {
1159          var message = 'delayed for ' + ai_cookie [block][cookie_block_property] + ' pageviews';
1160          ai_debug_cookie_status = message;
1161          if (ai_debug) console.log ('AI CHECK block', block, message);
1162          if (ai_debug) console.log ('');
1163
1164          return false;
1165        }
1166      } else
1167      if (cookie_block_property == 'i') {
1168
1169        var code_hash = '';
1170        var block_object = document.querySelectorAll ('span[data-ai-block="'+block+'"]') [0]
1171        if ("aiHash" in block_object.dataset) {
1172          code_hash = block_object.dataset.aiHash;
1173        }
1174
1175        var cookie_code_hash = '';
1176        if (ai_cookie [block].hasOwnProperty ('h')) {
1177          cookie_code_hash = ai_cookie [block]['h'];
1178        }
1179        if (ai_debug) console.log ('AI CHECK block', block, 'i cookie hash', cookie_code_hash, 'code hash', code_hash);
1180
1181        if (ai_cookie [block][cookie_block_property] == 0 && cookie_code_hash == code_hash) {
1182          var message = 'max impressions reached';
1183          ai_debug_cookie_status = message;
1184          if (ai_debug) console.log ('AI CHECK block', block, message);
1185          if (ai_debug) console.log ('');
1186
1187          return false;
1188        } else
1189
1190        if (ai_cookie [block][cookie_block_property] < 0 && cookie_code_hash == code_hash) {
1191          var date = new Date();
1192          var closed_for = - ai_cookie [block][cookie_block_property] - Math.round (date.getTime() / 1000);
1193          if (closed_for > 0) {
1194            var message = 'max imp. reached (' + Math. round (10000 * closed_for / 24 / 3600) / 10000 + ' days = ' + closed_for + ' s)';
1195            ai_debug_cookie_status = message;
1196            if (ai_debug) console.log ('AI CHECK block', block, message);
1197            if (ai_debug) console.log ('');
1198
1199            return false;
1200          } else {
1201              if (ai_debug) console.log ('AI CHECK block', block, 'removing i');
1202
1203              ai_set_cookie (block, 'i', '');
1204              if (!ai_cookie [block].hasOwnProperty ('c') && !ai_cookie [block].hasOwnProperty ('x')) {
1205                if (ai_debug) console.log ('AI CHECK block', block, 'cookie h removed');
1206
1207                ai_set_cookie (block, 'h', '');
1208              }
1209            }
1210        }
1211      }
1212      if (cookie_block_property == 'ipt') {
1213        if (ai_cookie [block][cookie_block_property] == 0) {
1214
1215          var date = new Date();
1216          var timestamp = Math.round (date.getTime() / 1000);
1217          var closed_for = ai_cookie [block]['it'] - timestamp;
1218
1219          if (closed_for > 0) {
1220            var message = 'max imp. per time reached (' + Math. round (10000 * closed_for / 24 / 3600) / 10000 + ' days = ' + closed_for + ' s)';
1221            ai_debug_cookie_status = message;
1222            if (ai_debug) console.log ('AI CHECK block', block, message);
1223            if (ai_debug) console.log ('');
1224
1225            return false;
1226          }
1227        }
1228      }
1229      if (cookie_block_property == 'c') {
1230
1231        var code_hash = '';
1232        var block_object = document.querySelectorAll ('span[data-ai-block="'+block+'"]') [0]
1233        if ("aiHash" in block_object.dataset) {
1234          code_hash = block_object.dataset.aiHash;
1235        }
1236
1237        var cookie_code_hash = '';
1238        if (ai_cookie [block].hasOwnProperty ('h')) {
1239          cookie_code_hash = ai_cookie [block]['h'];
1240        }
1241        if (ai_debug) console.log ('AI CHECK block', block, 'c cookie hash', cookie_code_hash, 'code hash', code_hash);
1242
1243        if (ai_cookie [block][cookie_block_property] == 0 && cookie_code_hash == code_hash) {
1244          var message = 'max clicks reached';
1245          ai_debug_cookie_status = message;
1246          if (ai_debug) console.log ('AI CHECK block', block, message);
1247          if (ai_debug) console.log ('');
1248
1249          return false;
1250        } else
1251
1252        if (ai_cookie [block][cookie_block_property] < 0 && cookie_code_hash == code_hash) {
1253          var date = new Date();
1254          var closed_for = - ai_cookie [block][cookie_block_property] - Math.round (date.getTime() / 1000);
1255          if (closed_for > 0) {
1256            var message = 'max clicks reached (' + Math. round (10000 * closed_for / 24 / 3600) / 10000 + ' days = ' + closed_for + ' s)';
1257            ai_debug_cookie_status = message;
1258            if (ai_debug) console.log ('AI CHECK block', block, message);
1259            if (ai_debug) console.log ('');
1260
1261            return false;
1262          } else {
1263              if (ai_debug) console.log ('AI CHECK block', block, 'removing c');
1264
1265              ai_set_cookie (block, 'c', '');
1266              if (!ai_cookie [block].hasOwnProperty ('i') && !ai_cookie [block].hasOwnProperty ('x')) {
1267                if (ai_debug) console.log ('AI CHECK block', block, 'cookie h removed');
1268
1269                ai_set_cookie (block, 'h', '');
1270              }
1271            }
1272        }
1273      }
1274      if (cookie_block_property == 'cpt') {
1275        if (ai_cookie [block][cookie_block_property] == 0) {
1276
1277          var date = new Date();
1278          var timestamp = Math.round (date.getTime() / 1000);
1279          var closed_for = ai_cookie [block]['ct'] - timestamp;
1280
1281          if (closed_for > 0) {
1282            var message = 'max clicks per time reached (' + Math. round (10000 * closed_for / 24 / 3600) / 10000 + ' days = ' + closed_for + ' s)';
1283            ai_debug_cookie_status = message;
1284            if (ai_debug) console.log ('AI CHECK block', block, message);
1285            if (ai_debug) console.log ('');
1286
1287            return false;
1288          }
1289        }
1290      }
1291    }
1292
1293    if (ai_cookie.hasOwnProperty ('G') && ai_cookie ['G'].hasOwnProperty ('cpt')) {
1294      if (ai_cookie ['G']['cpt'] == 0) {
1295
1296        var date = new Date();
1297        var timestamp = Math.round (date.getTime() / 1000);
1298        var closed_for = ai_cookie ['G']['ct'] - timestamp;
1299
1300        if (closed_for > 0) {
1301          var message = 'max global clicks per time reached (' + Math. round (10000 * closed_for / 24 / 3600) / 10000 + ' days = ' + closed_for + ' s)';
1302          ai_debug_cookie_status = message;
1303          if (ai_debug) console.log ('AI CHECK GLOBAL', message);
1304          if (ai_debug) console.log ('');
1305
1306          return false;
1307        }
1308      }
1309    }
1310  }
1311
1312  ai_debug_cookie_status = 'OK';
1313  if (ai_debug) console.log ('AI CHECK block', block, 'OK');
1314  if (ai_debug) console.log ('');
1315
1316  return true;
1317}
1318
1319ai_check_and_insert_block = function (block, id) {
1320
1321//  var ai_debug = typeof ai_debugging !== 'undefined'; // 2
1322  var ai_debug = false;
1323
1324  if (block == null) {
1325    return true;
1326  }
1327
1328  var ai_block_divs = document.getElementsByClassName (id);
1329  if (ai_block_divs.length) {
1330
1331    var ai_block_div = ai_block_divs [0];
1332    var wrapping_div = ai_block_div.closest ('.' + ai_block_class_def);
1333
1334    var insert_block = ai_check_block (block);
1335
1336    if (!insert_block) {
1337//      if (ai_debug) console.log ('AI CHECK FAILED, !insert_block', block);
1338      // Check for a fallback block
1339      if (parseInt (ai_block_div.getAttribute ('limits-fallback')) != 0 && ai_block_div.hasAttribute ('data-fallback-code')) {
1340
1341        if (ai_debug) console.log ('AI CHECK FAILED, INSERTING FALLBACK BLOCK', ai_block_div.getAttribute ('limits-fallback'));
1342
1343        ai_block_div.setAttribute ('data-code', ai_block_div.getAttribute ('data-fallback-code'));
1344
1345        if (wrapping_div != null && wrapping_div.hasAttribute ('data-ai')) {
1346          if (ai_block_div.hasAttribute ('fallback-tracking') && ai_block_div.hasAttribute ('fallback_level')) {
1347            wrapping_div.setAttribute ('data-ai-' + ai_block_div.getAttribute ('fallback_level'), ai_block_div.getAttribute ('fallback-tracking'));
1348          }
1349        }
1350
1351        insert_block = true;
1352      }
1353    }
1354
1355    // Remove selector to prevent further insertions at this element
1356    ai_block_div.removeAttribute ('data-selector');
1357
1358    if (insert_block) {
1359      ai_insert_code (ai_block_div);
1360
1361      if (wrapping_div) {
1362        var debug_block = wrapping_div.querySelectorAll ('.ai-debug-block');
1363        if (/*wrapping_div && */debug_block.length) {
1364          wrapping_div.classList.remove ('ai-list-block');
1365          wrapping_div.classList.remove ('ai-list-block-ip');
1366          wrapping_div.classList.remove ('ai-list-block-filter');
1367          wrapping_div.style.visibility = '';
1368          if (wrapping_div.classList.contains ('ai-remove-position')) {
1369            wrapping_div.style.position = '';
1370          }
1371        }
1372      }
1373    } else {
1374        var ai_block_div_data = ai_block_div.closest ('div[data-ai]');
1375        if (ai_block_div_data != null && typeof ai_block_div_data.getAttribute ("data-ai") != "undefined") {
1376          var data = JSON.parse (b64d (ai_block_div_data.getAttribute ("data-ai")));
1377          if (typeof data !== "undefined" && data.constructor === Array) {
1378            data [1] = "";
1379            ai_block_div_data.setAttribute ("data-ai", b64e (JSON.stringify (data)));
1380          }
1381        }
1382        if (wrapping_div) {
1383          var debug_block = wrapping_div.querySelectorAll ('.ai-debug-block');
1384          if (/*wrapping_div && */debug_block.length) {
1385            wrapping_div.classList.remove ('ai-list-block');
1386            wrapping_div.classList.remove ('ai-list-block-ip');
1387            wrapping_div.classList.remove ('ai-list-block-filter');
1388            wrapping_div.style.visibility = '';
1389            if (wrapping_div.classList.contains ('ai-remove-position')) {
1390              wrapping_div.style.position = '';
1391            }
1392          }
1393        }
1394      }
1395
1396    // Remove class
1397    ai_block_div.classList.remove (id);
1398  }
1399
1400  var ai_debug_bars = document.querySelectorAll ('.' + id + '-dbg');
1401
1402//  for (let ai_debug_bar of ai_debug_bars) {
1403  for (var index = 0, len = ai_debug_bars.length; index < len; index++) {
1404    var ai_debug_bar = ai_debug_bars [index];
1405    ai_debug_bar.querySelector ('.ai-status').textContent = ai_debug_cookie_status;
1406    ai_debug_bar.querySelector ('.ai-cookie-data').textContent = ai_get_cookie_text (block);
1407    ai_debug_bar.classList.remove (id + '-dbg');
1408  }
1409}
1410
1411ai_load_cookie = function () {
1412
1413//  var ai_debug = typeof ai_debugging !== 'undefined'; // 3
1414  var ai_debug = false;
1415
1416  var ai_cookie_name = 'aiBLOCKS';
1417
1418//  ###
1419//  var ai_cookie = AiCookies.getJSON (ai_cookie_name);
1420  var ai_cookie = ai_json_data (AiCookies.get (ai_cookie_name));
1421
1422  if (ai_cookie == null) {
1423    ai_cookie = {};
1424
1425    if (ai_debug) console.log ('AI COOKIE NOT PRESENT');
1426  }
1427
1428  if (ai_debug) console.log ('AI COOKIE LOAD', ai_cookie);
1429
1430  return ai_cookie;
1431}
1432
1433function ai_get_cookie (block, property) {
1434
1435//  var ai_debug = typeof ai_debugging !== 'undefined'; // 4
1436  var ai_debug = false;
1437
1438  var value = '';
1439  var ai_cookie = ai_load_cookie ();
1440
1441  if (ai_cookie.hasOwnProperty (block)) {
1442    if (ai_cookie [block].hasOwnProperty (property)) {
1443      value = ai_cookie [block][property];
1444    }
1445  }
1446
1447  if (ai_debug) console.log ('AI COOKIE GET block:', block, 'property:', property, 'value:', value);
1448
1449  return value;
1450}
1451
1452ai_set_cookie = function (block, property, value) {
1453
1454  function isEmpty (obj) {
1455    for (var key in obj) {
1456        if (obj.hasOwnProperty (key))
1457          return false;
1458    }
1459    return true;
1460  }
1461
1462  var ai_cookie_name = 'aiBLOCKS';
1463//  var ai_debug = typeof ai_debugging !== 'undefined'; // 5
1464  var ai_debug = false;
1465
1466  if (ai_debug) console.log ('AI COOKIE SET block:', block, 'property:', property, 'value:', value);
1467
1468  var ai_cookie = ai_load_cookie ();
1469
1470  if (value === '') {
1471    if (ai_cookie.hasOwnProperty (block)) {
1472      delete ai_cookie [block][property];
1473      if (isEmpty (ai_cookie [block])) {
1474        delete ai_cookie [block];
1475      }
1476    }
1477  } else {
1478      if (!ai_cookie.hasOwnProperty (block)) {
1479        ai_cookie [block] = {};
1480      }
1481      ai_cookie [block][property] = value;
1482    }
1483
1484  if (Object.keys (ai_cookie).length === 0 && ai_cookie.constructor === Object) {
1485    AiCookies.remove (ai_cookie_name);
1486
1487    if (ai_debug) console.log ('AI COOKIE REMOVED');
1488  } else {
1489//    ###
1490//      AiCookies.set (ai_cookie_name, ai_cookie, {expires: 365, path: '/'});
1491      AiCookies.set (ai_cookie_name, JSON.stringify (ai_cookie), {expires: 365, path: '/'});
1492    }
1493
1494  if (ai_debug) {
1495//    ###
1496//    var ai_cookie_test = AiCookies.getJSON (ai_cookie_name);
1497    var ai_cookie_test = ai_json_data (AiCookies.get (ai_cookie_name));
1498
1499    if (typeof (ai_cookie_test) != 'undefined') {
1500      console.log ('AI COOKIE NEW', ai_cookie_test);
1501
1502      console.log ('AI COOKIE DATA:');
1503      for (var cookie_block in ai_cookie_test) {
1504        for (var cookie_block_property in ai_cookie_test [cookie_block]) {
1505          if (cookie_block_property == 'x') {
1506            var date = new Date();
1507            var closed_for = ai_cookie_test [cookie_block][cookie_block_property] - Math.round (date.getTime() / 1000);
1508            console.log ('  BLOCK', cookie_block, 'closed for', closed_for, 's = ', Math.round (10000 * closed_for / 3600 / 24) / 10000, 'days');
1509          } else
1510          if (cookie_block_property == 'd') {
1511            console.log ('  BLOCK', cookie_block, 'delayed for', ai_cookie_test [cookie_block][cookie_block_property], 'pageviews');
1512          } else
1513          if (cookie_block_property == 'e') {
1514            console.log ('  BLOCK', cookie_block, 'show every', ai_cookie_test [cookie_block][cookie_block_property], 'pageviews');
1515          } else
1516          if (cookie_block_property == 'i') {
1517            var i = ai_cookie_test [cookie_block][cookie_block_property];
1518            if (i >= 0) {
1519              console.log ('  BLOCK', cookie_block, ai_cookie_test [cookie_block][cookie_block_property], 'impressions until limit');
1520            } else {
1521                var date = new Date();
1522                var closed_for = - i - Math.round (date.getTime() / 1000);
1523                console.log ('  BLOCK', cookie_block, 'max impressions, closed for', closed_for, 's =', Math.round (10000 * closed_for / 3600 / 24) / 10000, 'days');
1524              }
1525          } else
1526          if (cookie_block_property == 'ipt') {
1527            console.log ('  BLOCK', cookie_block, ai_cookie_test [cookie_block][cookie_block_property], 'impressions until limit per time period');
1528          } else
1529          if (cookie_block_property == 'it') {
1530            var date = new Date();
1531            var closed_for = ai_cookie_test [cookie_block][cookie_block_property] - Math.round (date.getTime() / 1000);
1532            console.log ('  BLOCK', cookie_block, 'impressions limit expiration in', closed_for, 's =', Math.round (10000 * closed_for / 3600 / 24) / 10000, 'days');
1533          } else
1534          if (cookie_block_property == 'c') {
1535            var c = ai_cookie_test [cookie_block][cookie_block_property]
1536            if (c >= 0) {
1537              console.log ('  BLOCK', cookie_block, c, 'clicks until limit');
1538            } else {
1539                var date = new Date();
1540                var closed_for = - c - Math.round (date.getTime() / 1000);
1541                console.log ('  BLOCK', cookie_block, 'max clicks, closed for', closed_for, 's =', Math.round (10000 * closed_for / 3600 / 24) / 10000, 'days');
1542              }
1543          } else
1544          if (cookie_block_property == 'cpt') {
1545            console.log ('  BLOCK', cookie_block, ai_cookie_test [cookie_block][cookie_block_property], 'clicks until limit per time period');
1546          } else
1547          if (cookie_block_property == 'ct') {
1548            var date = new Date();
1549            var closed_for = ai_cookie_test [cookie_block][cookie_block_property] - Math.round (date.getTime() / 1000);
1550            console.log ('  BLOCK', cookie_block, 'clicks limit expiration in ', closed_for, 's =', Math.round (10000 * closed_for / 3600 / 24) / 10000, 'days');
1551          } else
1552          if (cookie_block_property == 'h') {
1553            console.log ('  BLOCK', cookie_block, 'hash', ai_cookie_test [cookie_block][cookie_block_property]);
1554          } else
1555          console.log ('      ?:', cookie_block, ':', cookie_block_property, ai_cookie_test [cookie_block][cookie_block_property]);
1556        }
1557        console.log ('');
1558      }
1559    } else console.log ('AI COOKIE NOT PRESENT');
1560  }
1561
1562  return ai_cookie;
1563}
1564
1565ai_get_cookie_text = function (block) {
1566  var ai_cookie_name = 'aiBLOCKS';
1567//  ###
1568//  var ai_cookie = AiCookies.getJSON (ai_cookie_name);
1569  var ai_cookie = ai_json_data (AiCookies.get (ai_cookie_name));
1570
1571  if (ai_cookie == null) {
1572    ai_cookie = {};
1573  }
1574
1575  var global_data = '';
1576  if (ai_cookie.hasOwnProperty ('G')) {
1577    global_data = 'G[' + JSON.stringify (ai_cookie ['G']).replace (/\"/g, '').replace ('{', '').replace('}', '') + '] ';
1578  }
1579
1580  var block_data = '';
1581  if (ai_cookie.hasOwnProperty (block)) {
1582    block_data = JSON.stringify (ai_cookie [block]).replace (/\"/g, '').replace ('{', '').replace('}', '');
1583  }
1584
1585  return global_data + block_data;
1586}
1587
1588}
1589var ai_internal_tracking = 1;
1590var ai_external_tracking = 0;
1591
1592var ai_external_tracking_category  = "Ad Inserter Pro";
1593var ai_external_tracking_action    = "[EVENT]";
1594var ai_external_tracking_label     = "[BLOCK_NUMBER] - [BLOCK_VERSION_NAME]";
1595var ai_external_tracking_username  = "";
1596
1597var ai_track_pageviews = 0;
1598var ai_advanced_click_detection = 0;
1599var ai_viewport_widths = [980,768,0];
1600var ai_viewport_indexes = [1,2,3];
1601var ai_viewport_names_string = "WyJEZXNrdG9wIiwiVGFibGV0IiwiUGhvbmUiXQ==";
1602var ai_data_id = "b85c005be6";
1603var ai_ajax_url = 'https://the-gadgeteer.com/wp-admin/admin-ajax.php';
1604var ai_debug_tracking = 0;
1605var ai_adb_attribute = 'ZGF0YS1kYXRhLW1hc2s=';
1606if (typeof ai_internal_tracking !== 'undefined') {
1607
1608ai_viewport_names = JSON.parse (b64d (ai_viewport_names_string));
1609
1610function matchRuleShort (str, rule) {
1611  var escapeRegex = (str) => str.replace(/([.*+?^=!:${}()|\[\]\/\\])/g, "\\$1");
1612  return new RegExp("^" + rule.split("*").map(escapeRegex).join(".*") + "$").test(str);
1613}
1614
1615function ai_addEventListener (el, eventName, eventHandler, selector) {
1616  if (selector) {
1617    const wrappedHandler = (e) => {
1618      if (e.target && e.target.matches(selector)) {
1619        eventHandler(e);
1620      }
1621    };
1622    el.addEventListener (eventName, wrappedHandler);
1623    return wrappedHandler;
1624  } else {
1625    el.addEventListener (eventName, eventHandler);
1626    return eventHandler;
1627  }
1628}
1629
1630  // Tracking handler manager
1631  installIframeTracker = function (handler, target) {
1632    // Building handler object from handler function
1633    if (typeof handler == "function") {
1634      handler = {
1635        blurCallback: handler
1636      };
1637    }
1638
1639    if (handler === null || handler === false) {
1640      ai_iframeTracker.untrack (target);
1641    } else if (typeof handler == "object") {
1642      ai_iframeTracker.track (target, handler);
1643    } else {
1644      throw new Error ("Wrong handler type (must be an object, or null|false to untrack)");
1645    }
1646    return this;
1647  };
1648
1649  var ai_mouseoverHander = function (handler, event){
1650    event.data = {'handler': handler};
1651    ai_iframeTracker.mouseoverListener (event);
1652  }
1653  var ai_mouseoutHander = function (handler, event){
1654    event.data = {'handler': handler};
1655    ai_iframeTracker.mouseoutListener (event);
1656  }
1657
1658  // Iframe tracker common object
1659  ai_iframeTracker = {
1660    // State
1661    focusRetriever: null,  // Element used for restoring focus on window (element)
1662    focusRetrieved: false, // Says if the focus was retrieved on the current page (bool)
1663    handlersList: [],      // Store a list of every trakers (created by calling $(selector).iframeTracker...)
1664    isIE8AndOlder: false,  // true for Internet Explorer 8 and older
1665
1666    // Init (called once on document ready)
1667    init: function () {
1668      // Determine browser version (IE8-)
1669        try {
1670          // ### AI
1671          // To prevent replacement of regexp pattern with CDN url (CDN code bug)
1672          var msie_regexp = new RegExp ('(msie) ([\\w.]+)', 'i');
1673
1674//          var matches = navigator.userAgent.match(/(msie) ([\w.]+)/i);
1675          var matches = navigator.userAgent.match (msie_regexp);
1676          // ### /AI
1677
1678          if (matches [2] < 9) {
1679            this.isIE8AndOlder = true;
1680          }
1681        } catch (ex2) {}
1682
1683      // Listening window blur
1684      window.focus ();
1685
1686      window.addEventListener ('blur', (event) => {
1687        ai_iframeTracker.windowLoseFocus (event);
1688      });
1689
1690      // Focus retriever (get the focus back to the page, on mouse move)
1691      // ### AI
1692      // ### added label for tools like https://web.dev/measure/
1693      // ***
1694
1695      var focus_retriever_holder = document.createElement ('div');
1696      focus_retriever_holder.style = 'position:fixed; top:0; left:0; overflow:hidden;';
1697      focus_retriever_holder.innerHTML = '<input style="position:absolute; left:-300px;" type="text" value="" id="focus_retriever" readonly="true" aria-hidden="true" /><label for="focus_retriever">&nbsp;</label>';
1698      document.querySelector ('body').append (focus_retriever_holder);
1699
1700      // ### /AI
1701      this.focusRetriever = document.querySelector ("#focus_retriever");
1702      this.focusRetrieved = false;
1703
1704      // Special processing to make it work with my old friend IE8 (and older) ;)
1705      if (this.isIE8AndOlder) {
1706        // Blur doesn't works correctly on IE8-, so we need to trigger it manually
1707
1708        this.focusRetriever.blur (function (e) {
1709          e.stopPropagation ();
1710          e.preventDefault ();
1711          ai_iframeTracker.windowLoseFocus (e);
1712
1713        });
1714
1715        // Keep focus on window (fix bug IE8-, focusable elements)
1716        document.querySelector ('body').addEventListener ('click', (e) => {
1717          window.focus ();
1718        });
1719        document.querySelector ('form').addEventListener ('click', (e) => {
1720          e.stopPropagation ();
1721        });
1722
1723        // Same thing for "post-DOMready" created forms (issue #6)
1724        try {
1725          ai_addEventListener (document.querySelector ('body'), 'click', (e) => {e.stopPropagation();}, 'form');
1726        } catch (ex) {
1727          console.log ("[iframeTracker] error (exception: " + ex.message + ")");
1728        }
1729      }
1730    },
1731
1732    // Add tracker to target using handler (bind boundary listener + register handler)
1733    // target: Array of target elements (native DOM elements)
1734    // handler: User handler object
1735    track: function (target, handler) {
1736      // Adding target elements references into handler
1737      handler.target = target;
1738
1739      // Storing the new handler into handler list
1740      ai_iframeTracker.handlersList.push (handler);
1741
1742      // Binding boundary listener
1743      target.addEventListener ('mouseover', ai_mouseoverHander.bind (event, handler), false);
1744      target.addEventListener ('mouseout', ai_mouseoutHander.bind (event, handler), false);
1745    },
1746
1747    // Remove tracking on target elements
1748    // target: target element
1749    untrack: function (target) {
1750      if (typeof Array.prototype.filter != "function") {
1751        console.log ("Your browser doesn't support Array filter, untrack disabled");
1752        return;
1753      }
1754
1755      // Unbinding boundary listener
1756      target.forEach ((el, i) => {
1757        el.removeEventListener ('mouseover', ai_mouseoverHander, false);
1758        el.removeEventListener ('mouseout',  ai_mouseoutHander,  false);
1759      });
1760
1761      // Handler garbage collector
1762      var nullFilter = function(value) {
1763        return value === null ? false : true;
1764      };
1765      for (var i in this.handlersList) {
1766        // Prune target
1767        for (var j in this.handlersList [i].target) {
1768          if ($.inArray (this.handlersList [i].target [j], target) !== -1) {
1769            this.handlersList [i].target [j] = null;
1770          }
1771        }
1772        this.handlersList [i].target = this.handlersList[i].target.filter (nullFilter);
1773
1774        // Delete handler if unused
1775        if (this.handlersList [i].target.length === 0) {
1776          this.handlersList [i] = null;
1777        }
1778      }
1779      this.handlersList = this.handlersList.filter (nullFilter);
1780    },
1781
1782    // Target mouseover event listener
1783    mouseoverListener: function(e) {
1784      e.data.handler.over = true;
1785      ai_iframeTracker.retrieveFocus ();
1786      try {
1787        e.data.handler.overCallback (e.data.handler.target, e);
1788      } catch (ex) {}
1789    },
1790
1791    // Target mouseout event listener
1792    mouseoutListener: function(e) {
1793      e.data.handler.over = false;
1794      ai_iframeTracker.retrieveFocus ();
1795      try {
1796        e.data.handler.outCallback (e.data.handler.target, e);
1797      } catch (ex) {}
1798    },
1799
1800    // Give back focus from an iframe to parent page
1801    retrieveFocus: function() {
1802      if (document.activeElement && document.activeElement.tagName === "IFRAME") {
1803        var process_iframe = true;
1804
1805        // Do not process listed iframes
1806        if (document.activeElement.hasAttribute ('id') && typeof ai_ignore_iframe_ids !== "undefined" && ai_ignore_iframe_ids.constructor === Array) {
1807          var iframe_id = document.activeElement.id;
1808          ai_ignore_iframe_ids.forEach (function (ignored_id) {if (matchRuleShort (iframe_id, ignored_id)) process_iframe = false});
1809        }
1810
1811        if (process_iframe && document.activeElement.hasAttribute ('class') && typeof ai_ignore_iframe_classes !== "undefined" && ai_ignore_iframe_classes.constructor === Array) {
1812          var iframe_class = document.activeElement.className;
1813          ai_ignore_iframe_classes.forEach (function (ignored_class) {if (matchRuleShort (iframe_class, ignored_class)) process_iframe = false});
1814        }
1815
1816        if (process_iframe) {
1817          ai_iframeTracker.focusRetriever.focus ();
1818          ai_iframeTracker.focusRetrieved = true;
1819        }
1820      }
1821    },
1822
1823    // Calls blurCallback for every handler with over=true on window blur
1824    windowLoseFocus: function (e) {
1825      for (var i in this.handlersList) {
1826        if (this.handlersList [i].over === true) {
1827          try {
1828            this.handlersList [i].blurCallback (e);
1829          } catch (ex) {}
1830        }
1831      }
1832    }
1833  };
1834
1835function ai_ready (fn) {
1836  if (document.readyState === 'complete' || (document.readyState !== 'loading' && !document.documentElement.doScroll)) {
1837    fn ();
1838  } else {
1839     document.addEventListener ('DOMContentLoaded', fn);
1840  }
1841}
1842
1843  // Init the iframeTracker on document ready
1844function ai_init_IframeTracker () {
1845  ai_iframeTracker.init ();
1846}
1847
1848ai_ready (ai_init_IframeTracker);
1849
1850
1851ai_tracking_finished = false;
1852
1853function ai_tracking () {
1854
1855  if (ai_debug_tracking) {
1856    ai_ajax_url = ai_ajax_url + '?ai-debug-tracking=1';
1857  }
1858
1859  Number.isInteger = Number.isInteger || function (value) {
1860    return typeof value === "number" &&
1861           isFinite (value) &&
1862           Math.floor (value) === value;
1863  };
1864
1865  function replace_tags (text, event, block, block_name, block_counter, version, version_name) {
1866    text = text.replace ('[EVENT]',                 event);
1867    text = text.replace ('[BLOCK_NUMBER]',          block);
1868    text = text.replace ('[BLOCK_NAME]',            block_name);
1869    text = text.replace ('[BLOCK_COUNTER]',         block_counter);
1870    text = text.replace ('[VERSION_NUMBER]',        version);
1871    text = text.replace ('[VERSION_NAME]',          version_name);
1872    text = text.replace ('[BLOCK_VERSION_NUMBER]',  block + (version == 0 ? '' : ' - ' + version));
1873    text = text.replace ('[BLOCK_VERSION_NAME]',    block_name + (version_name == '' ? '' : ' - ' + version_name));
1874    text = text.replace ('[WP_USERNAME]',           ai_external_tracking_username);
1875
1876    return (text);
1877  }
1878
1879  function external_tracking (event, block, block_name, block_counter, version, version_name, non_interaction) {
1880
1881    var category = replace_tags (ai_external_tracking_category, event, block, block_name, block_counter, version, version_name);
1882    var action   = replace_tags (ai_external_tracking_action,   event, block, block_name, block_counter, version, version_name);
1883    var label    = replace_tags (ai_external_tracking_label,    event, block, block_name, block_counter, version, version_name);
1884
1885    var ai_debug = typeof ai_debugging !== 'undefined'; // 1
1886//    var ai_debug = false;
1887
1888    if (ai_debug) console.log ("AI TRACKING EXTERNAL", event, block, '["' + category + '", "' + action + '", "' + label + '"]');
1889
1890    if (typeof ai_external_tracking_event == 'function') {
1891      if (ai_debug) console.log ('AI TRACKING ai_external_tracking_event (' + block + ', ' + event + ', ' + category + ', ' + action + ', ' + label + ', ' + non_interaction + ')');
1892
1893      var event_data = {'event': event, 'block': block, 'block_name': block_name, 'block_counter': block_counter, 'version': version, 'version_name': version_name};
1894
1895      var result = ai_external_tracking_event (event_data, category, action, label, non_interaction);
1896
1897      if (ai_debug) console.log ('AI TRACKING ai_external_tracking_event ():', result);
1898
1899      if (result == 0) return;
1900    }
1901
1902//        Google Analytics
1903    if (typeof window.ga == 'function') {
1904      var ga_command = 'send';
1905
1906      if (typeof ai_ga_tracker_name == 'string') {
1907        ga_command = ai_ga_tracker_name + '.' + ga_command;
1908
1909        if (ai_debug) console.log ("AI TRACKING ai_ga_tracker_name:", ai_ga_tracker_name);
1910      } else {
1911          var trackers = ga.getAll();
1912
1913          if (trackers.length != 0) {
1914            var tracker_name = trackers [0].get ('name');
1915            if (tracker_name != 't0') {
1916              ga_command = tracker_name + '.' + ga_command;
1917
1918              if (ai_debug) console.log ("AI TRACKING ga tracker name:", tracker_name);
1919            }
1920          } else {
1921              if (ai_debug) console.log ("AI TRACKING no ga tracker");
1922            }
1923        }
1924
1925      ga (ga_command, 'event', {
1926        eventCategory: category,
1927        eventAction: action,
1928        eventLabel: label,
1929        nonInteraction: non_interaction
1930      });
1931
1932      if (ai_debug) console.log ("AI TRACKING Google Universal Analytics:", non_interaction);
1933    }
1934//    else
1935
1936    if (typeof window.gtag == 'function') {
1937      gtag ('event', 'impression', {
1938        'event_category': category,
1939        'event_action': action,
1940        'event_label': label,
1941        'non_interaction': non_interaction
1942      });
1943
1944      if (ai_debug) console.log ("AI TRACKING Global Site Tag:", non_interaction);
1945    }
1946//    else
1947
1948    if (typeof window.__gaTracker == 'function') {
1949      __gaTracker ('send', 'event', {
1950        eventCategory: category,
1951        eventAction: action,
1952        eventLabel: label,
1953        nonInteraction: non_interaction
1954      });
1955
1956      if (ai_debug) console.log ("AI TRACKING Google Universal Analytics by MonsterInsights:", non_interaction);
1957    }
1958//    else
1959
1960    if (typeof window.dataLayer == 'object') {
1961      window.dataLayer.push ({
1962          'event': 'tracking',
1963          'eventCategory': category,
1964          'eventAction': action,
1965          'eventLabel': label
1966      });
1967
1968      if (ai_debug) console.log ("AI TRACKING Google Tag Manager:", non_interaction);
1969    }
1970
1971    if (typeof _gaq == 'object') {
1972//      _gaq.push (['_trackEvent', category, action, label]);
1973      _gaq.push (['_trackEvent', category, action, label, undefined, non_interaction]);
1974
1975      if (ai_debug) console.log ("AI TRACKING Google Legacy Analytics:", non_interaction);
1976    }
1977
1978//        Matomo (Piwik)
1979    if (typeof _paq == 'object') {
1980      _paq.push (['trackEvent', category, action, label]);
1981
1982      if (ai_debug) console.log ("AI TRACKING Matomo");
1983    }
1984  }
1985
1986  function ai_click (data, click_type) {
1987
1988    var ai_debug = typeof ai_debugging !== 'undefined'; //2
1989//    var ai_debug = false;
1990
1991    var block         = data [0];
1992    var code_version  = data [1];
1993
1994    if (Number.isInteger (code_version)) {
1995
1996      if (typeof ai_check_data == 'undefined' && typeof ai_check_data_timeout == 'undefined') {
1997        if (ai_debug) console.log ('AI CHECK CLICK - DATA NOT SET YET');
1998
1999        ai_check_data_timeout = true;
2000        setTimeout (function() {if (ai_debug) console.log (''); if (ai_debug) console.log ('AI CHECK CLICK TIMEOUT'); ai_click (data, click_type);}, 2500);
2001        return;
2002      }
2003
2004      if (ai_debug) console.log ('AI CHECK CLICK block', block);
2005      if (ai_debug) console.log ('AI CHECK CLICK data', ai_check_data);
2006
2007      ai_cookie = ai_load_cookie ();
2008
2009      for (var cookie_block in ai_cookie) {
2010
2011        if (parseInt (block) != parseInt (cookie_block)) continue;
2012
2013        for (var cookie_block_property in ai_cookie [cookie_block]) {
2014          if (cookie_block_property == 'c') {
2015            if (ai_debug) console.log ('AI CHECK CLICKS block:', cookie_block);
2016
2017            var clicks = ai_cookie [cookie_block][cookie_block_property];
2018            if (clicks > 0) {
2019              if (ai_debug) console.log ('AI CLICK, block', cookie_block, 'remaining', clicks - 1, 'clicks');
2020
2021              ai_set_cookie (cookie_block, 'c', clicks - 1);
2022
2023              if (clicks == 1) {
2024                if (ai_debug) console.log ('AI CLICKS #1, closing block', block, '- no more clicks');
2025
2026                var cfp_time = document.querySelector ('span[data-ai-block="' + block + '"]').dataset.aiCfpTime;
2027                var date = new Date();
2028                var timestamp = Math.round (date.getTime() / 1000);
2029
2030                var closed_until = timestamp + 7 * 24 * 3600;
2031                ai_set_cookie (cookie_block, 'c', - closed_until);
2032
2033                setTimeout (function() {
2034                  document.querySelectorAll ('span[data-ai-block="' + block + '"]').forEach ((el, index) => {
2035                    var closest = el.closest ("div[data-ai]");
2036                    if (closest) {
2037                      closest.remove ();
2038                    }
2039                  });
2040                }, 50);
2041              } else ai_set_cookie (cookie_block, 'c', clicks - 1);
2042            }
2043          } else
2044
2045          if (cookie_block_property == 'cpt') {
2046            if (ai_debug) console.log ('AI CHECK CLICKS PER TIME PERIOD block:', cookie_block);
2047
2048            var clicks = ai_cookie [cookie_block][cookie_block_property];
2049            if (clicks > 0) {
2050              if (ai_debug) console.log ('AI CLICKS, block', cookie_block, 'remaining', clicks - 1, 'clicks per time period');
2051
2052              ai_set_cookie (cookie_block, 'cpt', clicks - 1);
2053
2054              if (clicks == 1) {
2055                if (ai_debug) console.log ('AI CLICKS, closing block', block, '- no more clicks per time period');
2056
2057                var cfp_time = document.querySelector ('span[data-ai-block="' + block + '"]').dataset.aiCfpTime;
2058
2059                var date = new Date();
2060                var timestamp = Math.round (date.getTime() / 1000);
2061
2062                var closed_until = ai_cookie [cookie_block]['ct'];
2063                ai_set_cookie (cookie_block, 'x', closed_until);
2064
2065                if (ai_debug) console.log ('AI CLICKS, closing block', block, 'for', closed_until - timestamp, 's');
2066
2067                setTimeout (function() {
2068                  document.querySelectorAll ('span[data-ai-block="' + block + '"]').forEach ((el, index) => {
2069                    var closest = el.closest ("div[data-ai]");
2070                    if (closest) {
2071                      closest.remove ();
2072                    }
2073                  });
2074                }, 75); // After CFP is processed
2075
2076                if (typeof cfp_time != 'undefined') {
2077                  if (ai_debug) console.log ('AI CLICKS CFP, closing block', block, 'for', cfp_time, 'days');
2078
2079                  var closed_until = timestamp + cfp_time * 24 * 3600;
2080
2081//                  if (ai_debug) console.log ('AI COOKIE x 3 block', block, 'closed_until', closed_until);
2082                  ai_set_cookie (block, 'x', closed_until);
2083
2084                  document.querySelectorAll ('span.ai-cfp').forEach ((el, index) => {
2085                    var cfp_block = el.dataset.aiBlock;
2086
2087                    if (ai_debug) console.log ('AI CLICKS CFP, closing block', cfp_block, 'for', cfp_time, 'days');
2088
2089                    var block_to_close = el;
2090
2091                    setTimeout (function() {
2092//                      block_to_close.closest ("div[data-ai]").remove ();
2093                      var closest = block_to_close.closest ("div[data-ai]");
2094                      if (closest) {
2095                        closest.remove ();
2096                      }
2097                    }, 50);
2098
2099//                  if (ai_debug) console.log ('AI COOKIE x 4 block', cfp_block, 'closed_until', closed_until);
2100                    ai_set_cookie (cfp_block, 'x', closed_until);
2101                  });
2102                }
2103              }
2104            } else {
2105                if (ai_check_data.hasOwnProperty (cookie_block) && ai_check_data [cookie_block].hasOwnProperty ('cpt') && ai_check_data [cookie_block].hasOwnProperty ('ct')) {
2106                  if (ai_cookie.hasOwnProperty (cookie_block) && ai_cookie [cookie_block].hasOwnProperty ('ct')) {
2107                    var date = new Date();
2108                    var closed_for = ai_cookie [cookie_block]['ct'] - Math.round (date.getTime() / 1000);
2109                    if (closed_for <= 0) {
2110                      if (ai_debug) console.log ('AI CLICKS, block', cookie_block, 'set max clicks period (', ai_check_data [cookie_block]['ct'], 'days =', ai_check_data [cookie_block]['ct'] * 24 * 3600, 's)');
2111
2112                      var timestamp = Math.round (date.getTime() / 1000);
2113
2114                      ai_set_cookie (cookie_block, 'cpt', ai_check_data [cookie_block]['cpt'] - 1);
2115                      ai_set_cookie (cookie_block, 'ct', Math.round (timestamp + ai_check_data [cookie_block]['ct'] * 24 * 3600));
2116                    }
2117                  }
2118                } else {
2119                    if (ai_cookie.hasOwnProperty (cookie_block) && ai_cookie [cookie_block].hasOwnProperty ('cpt')) {
2120                      if (ai_debug) console.log ('AI CLICKS, block', cookie_block, 'removing cpt');
2121
2122                      ai_set_cookie (cookie_block, 'cpt', '');
2123                    }
2124                    if (ai_cookie.hasOwnProperty (cookie_block) && ai_cookie [cookie_block].hasOwnProperty ('ct')) {
2125                      if (ai_debug) console.log ('AI CLICKS, block', cookie_block, 'removing ct');
2126
2127                      ai_set_cookie (cookie_block, 'ct', '');
2128                    }
2129                  }
2130              }
2131          }
2132        }
2133      }
2134
2135      if (ai_cookie.hasOwnProperty ('G') && ai_cookie ['G'].hasOwnProperty ('cpt')) {
2136        if (ai_debug) console.log ('AI CHECK GLOBAL CLICKS PER TIME PERIOD');
2137
2138        var clicks = ai_cookie ['G']['cpt'];
2139        if (clicks > 0) {
2140          if (ai_debug) console.log ('AI CLICKS, GLOBAL remaining', clicks - 1, 'clicks per time period');
2141
2142          ai_set_cookie ('G', 'cpt', clicks - 1);
2143
2144          if (clicks == 1) {
2145            if (ai_debug) console.log ('AI CLICKS, closing block', block, '- no more global clicks per time period');
2146
2147            var cfp_time = document.querySelector ('span[data-ai-block="' + block + '"]').dataset.aiCfpTime;
2148            var date = new Date();
2149            var timestamp = Math.round (date.getTime() / 1000);
2150
2151            var closed_until = ai_cookie ['G']['ct'];
2152            ai_set_cookie (block, 'x', closed_until);
2153
2154            if (ai_debug) console.log ('AI CLICKS, closing block', block, 'for', closed_until - timestamp, 's');
2155
2156            setTimeout (function() {
2157              document.querySelectorAll ('span[data-ai-block="' + block + '"]').forEach ((el, index) => {
2158                var closest = el.closest ("div[data-ai]");
2159                if (closest) {
2160                  closest.remove ();
2161                }
2162              });
2163            }, 75); // After CFP is processed
2164
2165            if (ai_debug) console.log ('AI CLICKS GLOBAL block', block, 'cfp_time', cfp_time);
2166
2167            if (typeof cfp_time != 'undefined') {
2168              if (ai_debug) console.log ('AI CLICKS GLOBAL CFP, closing block', block, 'for', cfp_time, 'days');
2169
2170              var closed_until = timestamp + cfp_time * 24 * 3600;
2171
2172//                if (ai_debug) console.log ('AI COOKIE x 3 block', block, 'closed_until', closed_until);
2173              ai_set_cookie (block, 'x', closed_until);
2174
2175              document.querySelectorAll ('span.ai-cfp').forEach ((el, index) => {
2176                var cfp_block = el.dataset.aiBlock;
2177                if (ai_debug) console.log ('AI CLICKS GLOBAL CFP, closing block', cfp_block, 'for', cfp_time, 'days');
2178
2179                var block_to_close = el;
2180                setTimeout (function() {
2181                  block_to_close.closest ("div[data-ai]").remove ();
2182                }, 50);
2183
2184//                if (ai_debug) console.log ('AI COOKIE x 4 block', cfp_block, 'closed_until', closed_until);
2185                ai_set_cookie (cfp_block, 'x', closed_until);
2186              });
2187            }
2188          }
2189        } else {
2190            if (ai_check_data.hasOwnProperty ('G') && ai_check_data ['G'].hasOwnProperty ('cpt') && ai_check_data ['G'].hasOwnProperty ('ct')) {
2191              if (ai_cookie.hasOwnProperty ('G') && ai_cookie ['G'].hasOwnProperty ('ct')) {
2192                var date = new Date();
2193                var closed_for = ai_cookie ['G']['ct'] - Math.round (date.getTime() / 1000);
2194                if (closed_for <= 0) {
2195                  if (ai_debug) console.log ('AI CLICKS GLOBAL set max clicks period (', ai_check_data ['G']['ct'], 'days =', ai_check_data ['G']['ct'] * 24 * 3600, 's)');
2196
2197                  var timestamp = Math.round (date.getTime() / 1000);
2198
2199                  ai_set_cookie ('G', 'cpt', ai_check_data ['G']['cpt'] - 1);
2200                  ai_set_cookie ('G', 'ct', Math.round (timestamp + ai_check_data ['G']['ct'] * 24 * 3600));
2201                }
2202              }
2203            } else {
2204                if (ai_cookie.hasOwnProperty ('G') && ai_cookie ['G'].hasOwnProperty ('cpt')) {
2205                  if (ai_debug) console.log ('AI CLICKS GLOBAL removing cpt');
2206
2207                  ai_set_cookie ('G', 'cpt', '');
2208                }
2209                if (ai_cookie.hasOwnProperty ('G') && ai_cookie ['G'].hasOwnProperty ('ct')) {
2210                  if (ai_debug) console.log ('AI CLICKS GLOBAL removing ct');
2211
2212                  ai_set_cookie ('G', 'ct', '');
2213                }
2214              }
2215          }
2216      }
2217
2218
2219      if (ai_debug) console.log ("AI CLICK: ", data, click_type);
2220
2221      if (ai_internal_tracking) {
2222        if (typeof ai_internal_tracking_no_clicks === 'undefined') {
2223
2224          var url_data = {
2225            action: "ai_ajax",
2226            ai_check: ai_data_id,
2227            click: block,
2228            version: code_version,
2229            type: click_type,
2230          };
2231
2232          var formBody = [];
2233          for (var property in url_data) {
2234            var encodedKey = encodeURIComponent (property);
2235            var encodedValue = encodeURIComponent (url_data [property]);
2236            formBody.push (encodedKey + "=" + encodedValue);
2237          }
2238          formBody = formBody.join ("&");
2239
2240          async function ai_post_clicks () {
2241            const response = await fetch (ai_ajax_url, {
2242              method: 'POST',
2243              headers: {
2244                'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
2245              },
2246              body: formBody
2247            });
2248
2249            const text = await response.text ();
2250
2251            return text;
2252          }
2253
2254          ai_post_clicks ().then (data => {
2255
2256              data = data.trim ();
2257              if (data != "") {
2258                var db_records = JSON.parse (data);
2259
2260                if (ai_debug) {
2261                  console.log ("AI DB RECORDS: ", db_records);
2262                }
2263
2264                if (typeof db_records ['#'] != 'undefined' && db_records ['#'] == block) {
2265                  // Reload cookie data
2266                  ai_cookie = ai_load_cookie ();
2267
2268                  var date = new Date();
2269                  var closed_until = Math.round (date.getTime() / 1000) + 12 * 3600;
2270
2271                  if (ai_debug) console.log ("AI SERVERSIDE LIMITED BLOCK:", block);
2272
2273                  if (!ai_cookie.hasOwnProperty (block) || !ai_cookie [block].hasOwnProperty ('x')) {
2274                    if (ai_debug) console.log ("AI SERVERSIDE LIMITED BLOCK:", block, ' not closed - closing for 12 hours');
2275
2276                    ai_set_cookie (block, 'x', closed_until);
2277                  }
2278
2279                  setTimeout (function () {
2280                    document.querySelectorAll ('span[data-ai-block="' + block + '"]').forEach ((el, index) => {
2281                      var closest = el.closest ("div[data-ai]");
2282                      if (closest) {
2283                        closest.remove ();
2284                      }
2285                    });
2286                  }, 50);
2287                }
2288
2289                if (ai_debug) {
2290                  var db_record = db_records ['='];
2291
2292                  if (typeof db_record != "undefined") {
2293                    if (typeof db_record == "string")
2294                      console.log ("AI CLICK " + block, code_version == 0 ? "" : "[" + code_version + "]", "(" + db_record + ")"); else
2295                        console.log ("AI CLICK " + block, code_version == 0 ? "" : "[" + code_version + "]", "(Views: " + db_record [4] + ", Clicks: " + db_record [5] + (click_type == "" ? "" : ", " + click_type) + ")");
2296                  }
2297                }
2298              } else if (ai_debug) console.log ("AI CLICK " + block, code_version == 0 ? "" : "[" + code_version + "]", "(NO DATA" + (click_type == "" ? "" : ", " + click_type) + ")");
2299
2300              if (ai_debug) console.log ('');
2301          });
2302        } else {
2303            if (ai_debug) console.log ("AI CLICK INTERNAL TRACKING DISABLED");
2304          }
2305      }
2306
2307      if (ai_external_tracking) {
2308        if (typeof ai_external_tracking_no_clicks === 'undefined') {
2309          var block_name         = data [2];
2310          var code_version_name  = data [3];
2311          var block_counter      = data [4];
2312
2313          external_tracking ("click", block, block_name, block_counter, code_version, code_version_name, false);
2314        } else {
2315            if (ai_debug) console.log ("AI CLICK EXTERNAL TRACKING DISABLED");
2316          }
2317      }
2318
2319      if (typeof ai_click_action == 'function') {
2320        if (ai_debug) console.log ('AI CLICK ai_click_action (' + block + ') CALLED');
2321
2322        ai_click_action (block, block_name, code_version, code_version_name);
2323      }
2324    }
2325  }
2326
2327  ai_install_standard_click_trackers = function (block_wrapper) {
2328    var ai_debug = typeof ai_debugging !== 'undefined'; // 3
2329//    var ai_debug = false;
2330
2331    if (typeof block_wrapper == 'undefined') {
2332      block_wrapper = document.querySelector ('body');
2333    }
2334
2335    var elements = block_wrapper.querySelectorAll ("div.ai-track[data-ai]");
2336
2337    var filtered_elements = [];
2338    elements.forEach ((element, i) => {
2339      if (!!(element.offsetWidth || element.offsetHeight || element.getClientRects ().length)) {
2340      // ### Excludes element also when class is found in rotation option
2341//      var ai_lazy_loading = $(this).find ('div.ai-lazy');
2342//      var ai_manual_loading = $(this).find ('div.ai-manual');
2343//      var ai_manual_loading_list = $(this).find ('div.ai-list-manual');
2344//      var ai_manual_loading_auto = $(this).find ('div.ai-manual-auto');
2345//      if (ai_lazy_loading.length == 0 && ai_manual_loading.length == 0 && ai_manual_loading_list.length == 0 && ai_manual_loading_auto.length == 0) filtered_elements = filtered_elements.add ($(this));
2346
2347      if (!element.querySelectorAll ('div.ai-lazy, div.ai-wait-for-interaction, div.ai-manual, div.ai-list-manual, div.ai-manual-auto, div.ai-delayed').length) filtered_elements.push (element);
2348      // ***
2349      }
2350    });
2351
2352    elements = filtered_elements;
2353
2354
2355    // Mark as tracked
2356    var processed_elements = [];
2357    elements.forEach ((element, i) => {
2358      element.classList.remove ('ai-track');
2359      processed_elements.push.apply (processed_elements, element.querySelectorAll ('a'));
2360    });
2361
2362    elements = processed_elements;
2363
2364    if (elements.length != 0) {
2365      if (ai_advanced_click_detection) {
2366        elements.forEach ((element, i) => {
2367          element.addEventListener ('click', () => {
2368            var wrapper = element.closest ("div[data-ai]");
2369            while (wrapper !== null && wrapper.hasAttribute ("data-ai")) {
2370              var data = JSON.parse (b64d (wrapper.getAttribute ("data-ai")));
2371              if (typeof data !== "undefined" && data.constructor === Array) {
2372                if (Number.isInteger (data [1])) {
2373                  if (!wrapper.classList.contains ("clicked")) {
2374                    wrapper.classList.add ("clicked");
2375                    ai_click (data, "a.click");
2376                  }
2377                }
2378              }
2379              wrapper = wrapper.parentElement.closest ("div[data-ai]");
2380            }
2381          });
2382        });
2383
2384        if (ai_debug) {
2385          elements.forEach ((element, i) => {
2386            var wrapper = element.closest ("div[data-ai]");
2387            if (wrapper !== null && wrapper.hasAttribute ("data-ai")) {
2388              var data = JSON.parse (b64d (wrapper.dataset.ai));
2389              if (typeof data !== "undefined" && data.constructor === Array) {
2390                if (Number.isInteger (data [1])) {
2391                  if (!wrapper.classList.contains ("clicked")) {
2392                    console.log ("AI STANDARD CLICK TRACKER for link installed on block", data [0]);
2393                  } else console.log ("AI STANDARD CLICK TRACKER for link NOT installed on block", data [0], "- has class clicked");
2394                } else console.log ("AI STANDARD CLICK TRACKER for link NOT installed on block", data [0], "- version not set");
2395
2396              }
2397            }
2398          });
2399        }
2400      } else {
2401          elements.forEach ((element, i) => {
2402            element.addEventListener ('click', () => {
2403              var wrapper = element.closest ("div[data-ai]");
2404              while (wrapper !== null && wrapper.hasAttribute ("data-ai")) {
2405                var data = JSON.parse (b64d (wrapper.getAttribute ("data-ai")));
2406                if (typeof data !== "undefined" && data.constructor === Array) {
2407                  if (Number.isInteger (data [1])) {
2408                    ai_click (data, "a.click");
2409                    clicked = true;
2410                  }
2411                }
2412                wrapper = wrapper.parentElement.closest ("div[data-ai]");
2413              }
2414            });
2415          });
2416
2417          if (ai_debug) {
2418            elements.forEach ((element, i) => {
2419              var wrapper = element.closest ("div[data-ai]");
2420              if (wrapper !== null && wrapper.hasAttribute ("data-ai")) {
2421                var data = JSON.parse (b64d (wrapper.getAttribute ("data-ai")));
2422
2423                if (typeof data !== "undefined" && data.constructor === Array) {
2424                  if (Number.isInteger (data [1])) {
2425                    console.log ("AI STANDARD CLICK TRACKER installed on block", data [0]);
2426                  } else console.log ("AI STANDARD CLICK TRACKER NOT installed on block", data [0], "- version not set");
2427
2428                }
2429              }
2430            });
2431          }
2432        }
2433    }
2434  }
2435
2436  ai_install_click_trackers = function (block_wrapper) {
2437
2438    var ai_debug = typeof ai_debugging !== 'undefined'; // 4
2439//    var ai_debug = false;
2440
2441    if (typeof block_wrapper == 'undefined') {
2442      block_wrapper = document.querySelector ('body');
2443      if (ai_debug) console.log ("AI INSTALL CLICK TRACKERS");
2444    }  else if (ai_debug) console.log ("AI INSTALL CLICK TRACKERS:", block_wrapper.tagName, block_wrapper.getAttribute ('class'));
2445
2446
2447    if (ai_advanced_click_detection) {
2448                                                       // timed rotation options that may contain blocks for tracking (block shortcodes) - only currently active option is visible
2449      var elements = block_wrapper.querySelectorAll ("div.ai-track[data-ai], div.ai-rotate[data-info] div.ai-track[data-ai]");
2450
2451      var all_elements = [];
2452      elements.forEach ((element, i) => {
2453        // Install iframe click tracker only for visible blocks
2454        if (!!(element.offsetWidth || element.offsetHeight || element.getClientRects ().length)) {
2455          all_elements.push (element);
2456        }
2457      });
2458
2459      if (block_wrapper.hasAttribute ("data-ai") && block_wrapper.classList.contains ('ai-track') && !!(block_wrapper.offsetWidth || block_wrapper.offsetHeight || block_wrapper.getClientRects ().length)) {
2460        all_elements.push (block_wrapper);
2461      }
2462
2463      var filtered_elements = [];
2464      all_elements.forEach ((element, i) => {
2465
2466        // ### Excludes element also when class is found in rotation option
2467//        var ai_lazy_loading = $(this).find ('div.ai-lazy');
2468//        var ai_manual_loading = $(this).find ('div.ai-manual');
2469//        var ai_manual_loading_auto = $(this).find ('div.ai-manual-auto');
2470//        if (ai_lazy_loading.length == 0 && ai_manual_loading.length == 0 && ai_manual_loading_auto.length == 0) filtered_elements = filtered_elements.add ($(this));
2471
2472        if (!element.querySelectorAll ('div.ai-lazy, div.ai-wait-for-interaction, div.ai-manual, div.ai-list-manual, div.ai-manual-auto, div.ai-delayed').length) filtered_elements.push (element);
2473      });
2474
2475      elements = filtered_elements;
2476
2477    // Mark as tracked - prevents ai_install_standard_click_trackers
2478
2479//      var processed_elements = [];
2480//      elements.forEach ((element, i) => {
2481//        element.classList.remove ('ai-track');
2482//        processed_elements.push (processed_elements);
2483//      });
2484//      elements = processed_elements;
2485
2486    // Will be marked in ai_install_standard_click_trackers
2487
2488      if (elements.length != 0) {
2489        // ***
2490//        elements.iframeTracker ({
2491        elements.forEach ((element, i) => {
2492          installIframeTracker ({
2493
2494          blurCallback: function(){
2495            if (this.ai_data != null && wrapper != null) {
2496              if (ai_debug) console.log ("AI blurCallback for block: " + this.ai_data [0]);
2497              if (!wrapper.classList.contains ("clicked")) {
2498                wrapper.classList.add ("clicked");
2499                ai_click (this.ai_data, "blurCallback");
2500
2501                var inner_wrapper = wrapper.querySelector ("div[data-ai]");
2502                while (inner_wrapper != null && !!(inner_wrapper.offsetWidth || inner_wrapper.offsetHeight || inner_wrapper.getClientRects ().length) && inner_wrapper.hasAttribute ("data-ai")) {
2503                  var data = JSON.parse (b64d (inner_wrapper.getAttribute ("data-ai")));
2504                  if (typeof data !== "undefined" && data.constructor === Array && Number.isInteger (data [1])) {
2505                    ai_click (data, "blurCallback INNER");
2506                  }
2507                  inner_wrapper = inner_wrapper.querySelector ("div[data-ai]");
2508                }
2509              }
2510            }
2511          },
2512          overCallback: function(element){
2513            var closest = element.closest ("div[data-ai]");
2514            if (closest.hasAttribute ("data-ai")) {
2515              var data = JSON.parse (b64d (closest.getAttribute ("data-ai")));
2516              if (typeof data !== "undefined" && data.constructor === Array && Number.isInteger (data [1])) {
2517                wrapper = closest;
2518                this.ai_data = data;
2519                if (ai_debug) console.log ("AI overCallback for block: " + this.ai_data [0]);
2520              } else {
2521                  if (wrapper != null) wrapper.classList.remove ("clicked");
2522                  wrapper        = null;
2523                  this.ai_data  = null;
2524                }
2525            }
2526          },
2527          outCallback: function (element){
2528            if (ai_debug && this.ai_data != null) console.log ("AI outCallback for block: " + this.ai_data [0]);
2529            if (wrapper != null) wrapper.classList.remove ("clicked");
2530            wrapper = null;
2531            this.ai_data = null;
2532          },
2533          focusCallback: function(element){
2534            if (this.ai_data != null && wrapper != null) {
2535              if (ai_debug) console.log ("AI focusCallback for block: " + this.ai_data [0]);
2536              if (!wrapper.classList.contains ("clicked")) {
2537                wrapper.classList.add ("clicked");
2538                ai_click (this.ai_data, "focusCallback");
2539
2540                var inner_wrapper = wrapper.querySelector ("div[data-ai]");
2541
2542                while (inner_wrapper != null && !!(inner_wrapper.offsetWidth || inner_wrapper.offsetHeight || inner_wrapper.getClientRects ().length) && inner_wrapper.hasAttribute ("data-ai")) {
2543                  var data = JSON.parse (b64d (inner_wrapper.getAttribute ("data-ai")));
2544                  if (typeof data !== "undefined" && data.constructor === Array && Number.isInteger (data [1])) {
2545                    ai_click (data, "focusCallback INNER");
2546                  }
2547                  inner_wrapper = inner_wrapper.querySelector ("div[data-ai]");
2548                }
2549              }
2550            }
2551          },
2552          wrapper:  null,
2553          ai_data: null,
2554          block:   null,
2555          version: null
2556        }
2557        , element
2558        );
2559        });
2560
2561        if (ai_debug) {
2562          elements.forEach ((element, i) => {
2563            var closest = element.closest ("div[data-ai]");
2564            if (closest.hasAttribute ("data-ai")) {
2565              var data = JSON.parse (b64d (closest.getAttribute ("data-ai")));
2566              if (typeof data !== "undefined" && data.constructor === Array) {
2567                console.log ("AI ADVANCED CLICK TRACKER installed on block", data [0]);
2568              }
2569            }
2570          });
2571        }
2572      }
2573    }
2574
2575
2576    ai_install_standard_click_trackers (block_wrapper);
2577  }
2578
2579  var pageview_data = [];
2580
2581  ai_process_impressions = function (block_wrapper) {
2582
2583    var ai_debug = typeof ai_debugging !== 'undefined'; // 5
2584//    var ai_debug = false;
2585
2586    if (typeof block_wrapper == 'undefined') {
2587      block_wrapper = document.querySelector ('body');
2588      if (ai_debug) console.log ("AI PROCESS IMPRESSIONS");
2589    } else if (ai_debug) console.log ("AI PROCESS IMPRESSIONS:", block_wrapper.tagName, block_wrapper.hasAttribute ('class') ? block_wrapper.getAttribute ('class') : '');
2590
2591    var blocks = [];
2592    var versions = [];
2593    var block_names = [];
2594    var version_names = [];
2595    var block_counters = [];
2596    var version_indexes = [];
2597
2598    if (pageview_data.length != 0) {
2599      if (ai_debug) console.log ('AI PROCESS IMPRESSIONS - SENDING ALSO PAGEVIEW DATA', pageview_data);
2600
2601      blocks.push          (pageview_data [0]);
2602      versions.push        (pageview_data [1]);
2603      block_names.push     ('Pageviews');
2604      block_counters.push  (0);
2605      version_names.push   ('');
2606    }
2607
2608                                                                // timed rotation options that may contain blocks for tracking (block shortcodes) - only currently active option is visible
2609    var blocks_for_tracking = block_wrapper.querySelectorAll ("div.ai-track[data-ai], div.ai-rotate[data-info] div.ai-track[data-ai]");
2610    var visible_elements = [];
2611    blocks_for_tracking.forEach ((element, i) => {
2612      if (!!(element.offsetWidth || element.offsetHeight || element.getClientRects ().length) && !element.classList.contains ('ai-no-pageview')) {
2613        visible_elements.push (element);
2614      }
2615    });
2616
2617    if (block_wrapper !== null && block_wrapper.hasAttribute ("data-ai") && block_wrapper.classList.contains ('ai-track') && !block_wrapper.classList.contains ('ai-no-pageview') && !!(block_wrapper.offsetWidth || block_wrapper.offsetHeight || block_wrapper.getClientRects ().length)) {
2618      visible_elements.push (block_wrapper);
2619    }
2620    blocks_for_tracking = visible_elements;;
2621
2622    if (ai_debug) {
2623      console.log ("AI BLOCKS FOR TRACKING:");
2624      blocks_for_tracking.forEach ((element, i) => {console.log ('  ', element.getAttribute ('class'))});
2625    }
2626
2627    if (blocks_for_tracking.length != 0) {
2628      if (ai_debug) console.log ("");
2629
2630      blocks_for_tracking.forEach ((element, i) => {
2631
2632        if (element.hasAttribute ("data-ai")) {
2633
2634
2635          // Check for fallback tracking
2636          var new_tracking_data = '';
2637
2638          if (ai_debug && element.hasAttribute ('data-ai-1')) console.log ('AI TRACKING CHECKING BLOCK', element.getAttribute ('class'));
2639
2640          for (var fallback_level = 1; fallback_level <= 9; fallback_level ++) {
2641            if (element.hasAttribute ('data-ai-' + fallback_level)) {
2642              new_tracking_data = element.getAttribute ('data-ai-' + fallback_level);
2643
2644              if (ai_debug) console.log ('  FALLBACK LEVEL', fallback_level);
2645            } else break;
2646          }
2647
2648          if (new_tracking_data != '') {
2649            element.setAttribute ('data-ai', new_tracking_data);
2650            if (ai_debug) console.log ('  TRACKING DATA UPDATED TO', b64d (element.getAttribute ('data-ai')));
2651          }
2652
2653          var data = JSON.parse (b64d (element.getAttribute ("data-ai")));
2654
2655          if (typeof data !== "undefined" && data.constructor === Array) {
2656            if (ai_debug) console.log ("AI TRACKING DATA:", data);
2657
2658            var timed_rotation_count = 0;
2659            var ai_rotation_info = element.querySelectorAll ('div.ai-rotate[data-info]');
2660            if (ai_rotation_info.length == 1) {
2661              var block_rotation_info = JSON.parse (b64d (ai_rotation_info [0].dataset.info));
2662
2663              if (ai_debug) console.log ("AI TIMED ROTATION DATA:", block_rotation_info);
2664
2665              timed_rotation_count = block_rotation_info [1];
2666
2667              // Get version indexes
2668              version_indexes = [];
2669              var ai_rotation_versions = element.querySelectorAll ('div.ai-rotate .ai-rotate-option[data-index]').forEach ((el, index) => {
2670                var version_index = parseInt (el.dataset.index);
2671                version_indexes.push (version_index);
2672
2673                // There can be less optiosn than the highest option index
2674                if (version_index > timed_rotation_count) {
2675                  timed_rotation_count = version_index;
2676                }
2677              });
2678              if (ai_debug) console.log ("AI TIMED ROTATION VERSION INDEXES:", version_indexes);
2679              if (ai_debug) console.log ("AI TIMED ROTATION VERSIONS:", timed_rotation_count);
2680            }
2681
2682            if (Number.isInteger (data [0]) && data [0] != 0) {
2683              if (Number.isInteger (data [1])) {
2684
2685                var adb_flag = 0;
2686                // Deprecated
2687                var no_tracking = element.classList.contains ('ai-no-tracking');
2688
2689                var ai_masking_data = document.querySelector (b64d ("Ym9keQ==")).getAttribute (b64d (ai_adb_attribute));
2690                if (typeof ai_masking_data === "string") {
2691                  var ai_masking = ai_masking_data == b64d ("bWFzaw==");
2692                }
2693
2694                if (typeof ai_masking_data === "string" && typeof ai_masking === "boolean") {
2695                  var outer_height = element.offsetHeight;
2696
2697                  var ai_attributes = element.querySelectorAll ('.ai-attributes');
2698                  if (ai_attributes.length) {
2699                    ai_attributes.forEach ((el, i) => {
2700                      if (outer_height >= element.offsetHeight) {
2701                        outer_height -= element.offsetHeight;
2702                      }
2703                    });
2704                  }
2705
2706                  var ai_code = element.querySelectorAll ('.ai-code');
2707                  outer_height = 0;
2708                  if (ai_code.length) {
2709                    ai_code.forEach ((element, i) => {
2710                      outer_height += element.offsetHeight;
2711                    });
2712                  }
2713
2714  //                no_tracking = $(this).hasClass ('ai-no-tracking');
2715                  if (ai_debug) console.log ('AI ad blocking:', ai_masking, " offsetHeight:", outer_height, 'no tracking:', no_tracking);
2716                  if (ai_masking && outer_height === 0) {
2717                    adb_flag = 0x80;
2718                  }
2719                }
2720
2721//                var ai_lazy_loading = $(this).find ('div.ai-lazy');
2722//                var ai_manual_loading = $(this).find ('div.ai-manual');
2723//                var ai_manual_loading_list = $(this).find ('div.ai-list-manual');
2724//                var ai_manual_loading_auto = $(this).find ('div.ai-manual-auto');
2725
2726//                if (ai_lazy_loading.length != 0 || ai_manual_loading.length != 0 || ai_manual_loading_list.length != 0 || ai_manual_loading_auto.length != 0) {
2727
2728                if (element.querySelectorAll ('div.ai-lazy, div.ai-wait-for-interaction, div.ai-manual, div.ai-list-manual, div.ai-manual-auto, div.ai-delayed').length != 0) {
2729                  no_tracking = true;
2730
2731                  if (ai_debug) {
2732                    if (element.querySelectorAll ('div.ai-lazy').length   != 0) console.log ("AI TRACKING block", data [0], "is set for lazy loading");
2733                    if (element.querySelectorAll ('div.ai-wait-for-interaction').length   != 0) console.log ("AI TRACKING block", data [0], "is waiting for interaction");
2734                    if (element.querySelectorAll ('div.ai-manual').length != 0) console.log ("AI TRACKING block", data [0], "is set for manual loading");
2735                    if (element.querySelectorAll ('div.ai-list-manual').length != 0) console.log ("AI TRACKING block", data [0], "is set for manual loading AUTO list");
2736                    if (element.querySelectorAll ('div.ai-manual-auto').length != 0) console.log ("AI TRACKING block", data [0], "is set for manual loading AUTO");
2737                    if (element.querySelectorAll ('div.ai-delayed').length != 0) console.log ("AI TRACKING block", data [0], "is set for delayed loading");
2738                  }
2739                }
2740
2741                if (!no_tracking) {
2742                  if (timed_rotation_count == 0) {
2743                    blocks.push (data [0]);
2744                    versions.push (data [1] | adb_flag);
2745                    block_names.push (data [2]);
2746                    version_names.push (data [3]);
2747                    block_counters.push (data [4]);
2748                  } else {
2749                      // Timed rotation
2750                      for (var option = 1; option <= timed_rotation_count; option ++) {
2751                        if (version_indexes.includes (option)) {
2752                          blocks.push (data [0]);
2753                          versions.push (option | adb_flag);
2754                          block_names.push (data [2]);
2755                          version_names.push (data [3]);
2756                          block_counters.push (data [4]);
2757                        }
2758                      }
2759
2760                      element.classList.add ("ai-impression");
2761                    }
2762
2763                } else if (ai_debug) console.log ("AI TRACKING block", data [0], "DISABLED");
2764
2765              } else if (ai_debug) console.log ("AI TRACKING block", data [0], "- version not set", element.querySelectorAll ('div.ai-lazy').length != 0 ? 'LAZY LOADING' : '', element.querySelectorAll ('div.ai-wait-for-interaction').length != 0 ? 'WAITING FOR INTERACTION' : '', (element.querySelectorAll ('div.ai-manual').length + element.querySelectorAll ('div.ai-list-manual').length + element.querySelectorAll ('div.ai-manual-auto').length) != 0 ? 'MANUAL LOADING' : '');
2766            } else if (ai_debug) console.log ("AI TRACKING DISABLED");
2767          }
2768        }
2769      });
2770    }
2771
2772    if (ai_debug) console.log ('AI CHECK IMPRESSIONS blocks', blocks);
2773    if (ai_debug) console.log ('AI CHECK IMPRESSIONS data', ai_check_data);
2774
2775    ai_cookie = ai_load_cookie ();
2776
2777    for (var cookie_block in ai_cookie) {
2778
2779      if (!blocks.includes (parseInt (cookie_block))) continue;
2780
2781      for (var cookie_block_property in ai_cookie [cookie_block]) {
2782        if (cookie_block_property == 'i') {
2783          if (ai_debug) console.log ('AI CHECK IMPRESSIONS block:', cookie_block);
2784
2785          var impressions = ai_cookie [cookie_block][cookie_block_property];
2786          if (impressions > 0) {
2787            if (ai_debug) console.log ('AI IMPRESSION, block', cookie_block, 'remaining', impressions - 1, 'impressions');
2788
2789            if (impressions == 1) {
2790              var date = new Date();
2791                var closed_until = Math.round (date.getTime() / 1000) + 7 * 24 * 3600;
2792//              // TEST
2793//              var closed_until = Math.round (date.getTime() / 1000) + 36;
2794              ai_set_cookie (cookie_block, 'i', - closed_until);
2795            } else ai_set_cookie (cookie_block, 'i', impressions - 1);
2796          }
2797        } else
2798
2799        if (cookie_block_property == 'ipt') {
2800          if (ai_debug) console.log ('AI CHECK IMPRESSIONS PER TIME PERIOD block:', cookie_block);
2801
2802          var impressions = ai_cookie [cookie_block][cookie_block_property];
2803          if (impressions > 0) {
2804            if (ai_debug) console.log ('AI IMPRESSIONS, block', cookie_block, 'remaining', impressions - 1, 'impressions per time period');
2805
2806            ai_set_cookie (cookie_block, 'ipt', impressions - 1);
2807          } else {
2808              if (ai_check_data.hasOwnProperty (cookie_block) && ai_check_data [cookie_block].hasOwnProperty ('ipt') && ai_check_data [cookie_block].hasOwnProperty ('it')) {
2809                if (ai_cookie.hasOwnProperty (cookie_block) && ai_cookie [cookie_block].hasOwnProperty ('it')) {
2810                  var date = new Date();
2811                  var closed_for = ai_cookie [cookie_block]['it'] - Math.round (date.getTime() / 1000);
2812                  if (closed_for <= 0) {
2813                    if (ai_debug) console.log ('AI IMPRESSIONS, block', cookie_block, 'set max impressions period (' + ai_check_data [cookie_block]['it'], 'days =', ai_check_data [cookie_block]['it'] * 24 * 3600, 's)');
2814
2815                    var timestamp = Math.round (date.getTime() / 1000);
2816
2817                    ai_set_cookie (cookie_block, 'ipt', ai_check_data [cookie_block]['ipt']);
2818                    ai_set_cookie (cookie_block, 'it', Math.round (timestamp + ai_check_data [cookie_block]['it'] * 24 * 3600));
2819                  }
2820                }
2821              } else {
2822                  if (ai_cookie.hasOwnProperty (cookie_block) && ai_cookie [cookie_block].hasOwnProperty ('ipt')) {
2823                    if (ai_debug) console.log ('AI IMPRESSIONS, block', cookie_block, 'removing ipt');
2824
2825                    ai_set_cookie (cookie_block, 'ipt', '');
2826                  }
2827                  if (ai_cookie.hasOwnProperty (cookie_block) && ai_cookie [cookie_block].hasOwnProperty ('it')) {
2828                    if (ai_debug) console.log ('AI IMPRESSIONS, block', cookie_block, 'removing it');
2829
2830                    ai_set_cookie (cookie_block, 'it', '');
2831                  }
2832                }
2833            }
2834        }
2835      }
2836    }
2837
2838    if (blocks.length) {
2839      if (ai_debug) {
2840        console.log ("AI IMPRESSION blocks:", blocks);
2841        console.log ("            versions:", versions);
2842      }
2843
2844      if (ai_internal_tracking) {
2845        if (typeof ai_internal_tracking_no_impressions === 'undefined') {
2846
2847          // Mark as sent
2848          pageview_data = [];
2849
2850          var url_data = {
2851            action: "ai_ajax",
2852            ai_check: ai_data_id,
2853          };
2854
2855          var formBody = [];
2856          for (var property in url_data) {
2857            var encodedKey = encodeURIComponent (property);
2858            var encodedValue = encodeURIComponent (url_data [property]);
2859            formBody.push (encodedKey + "=" + encodedValue);
2860          }
2861
2862          for (var index in blocks) {
2863            var encodedKey = encodeURIComponent ('views[]');
2864            var encodedValue = encodeURIComponent (blocks [index]);
2865            formBody.push (encodedKey + "=" + encodedValue);
2866          }
2867
2868          for (var index in versions) {
2869            var encodedKey = encodeURIComponent ('versions[]');
2870            var encodedValue = encodeURIComponent (versions [index]);
2871            formBody.push (encodedKey + "=" + encodedValue);
2872          }
2873
2874          formBody = formBody.join ("&");
2875
2876          async function ai_post_views () {
2877            const response = await fetch (ai_ajax_url, {
2878              method: 'POST',
2879              headers: {
2880                'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
2881              },
2882              body: formBody
2883            });
2884
2885            const text = await response.text ();
2886            return text;
2887          }
2888
2889          ai_post_views ().then (data => {
2890
2891              data = data.trim ();
2892              if (data != "") {
2893                var db_records = JSON.parse (data);
2894
2895                if (ai_debug) console.log ("AI DB RECORDS: ", db_records);
2896
2897                if (typeof db_records ['#'] != 'undefined') {
2898                  // Reload cookie data
2899                  ai_cookie = ai_load_cookie ();
2900
2901                  var date = new Date();
2902                  var closed_until = Math.round (date.getTime() / 1000) + 12 * 3600;
2903
2904                  var blocks_to_remove = new Array();
2905                  for (var limited_block_index in db_records ['#']) {
2906                    if (ai_debug) console.log ("AI SERVERSIDE LIMITED BLOCK:", db_records ['#'][limited_block_index]);
2907
2908                    // Not needed as they will remain closed from the next page load
2909//                    blocks_to_remove.push (db_records ['#'][limited_block_index]);
2910
2911                    if (!ai_cookie.hasOwnProperty (db_records ['#'][limited_block_index]) || !ai_cookie [db_records ['#'][limited_block_index]].hasOwnProperty ('x')) {
2912                      if (ai_debug) console.log ("AI SERVERSIDE LIMITED BLOCK:", db_records ['#'][limited_block_index], ' not closed - closing for 12 hours');
2913
2914                      ai_set_cookie (db_records ['#'][limited_block_index], 'x', closed_until);
2915                    }
2916                  }
2917
2918                  setTimeout (function () {
2919                    for (index = 0; index < blocks_to_remove.length; ++index) {
2920                      document.querySelectorAll ('span[data-ai-block="' + blocks_to_remove [index] + '"]').forEach ((el, index) => {
2921                        var closest = el.closest ("div[data-ai]");
2922                        if (closest) {
2923                          closest.remove ();
2924                        }
2925                      });
2926                    }
2927                  }, 50);
2928                }
2929
2930                if (ai_debug) console.log ('');
2931              }
2932
2933          });
2934        } else {
2935            if (ai_debug) console.log ("AI PROCESS IMPRESSIONS INTERNAL TRACKING DISABLED");
2936          }
2937      }
2938
2939      if (ai_external_tracking) {
2940        if (typeof ai_external_tracking_no_impressions === 'undefined') {
2941          for (var i = 0; i < blocks.length; i++) {
2942            // Skip pageview data
2943            if (blocks [i] != 0) {
2944              external_tracking ("impression", blocks [i],  block_names [i], block_counters [i], versions [i], version_names [i], true);
2945            }
2946          }
2947        } else {
2948            if (ai_debug) console.log ("AI PROCESS IMPRESSIONS EXTERNAL TRACKING DISABLED");
2949          }
2950      }
2951    }
2952  }
2953
2954  function ai_process_pageview_checks () {
2955
2956    var ai_debug = typeof ai_debugging !== 'undefined'; // 6
2957//    var ai_debug = false;
2958
2959    ai_check_data = {};
2960
2961    if (typeof ai_iframe != 'undefined') return;
2962
2963    if (ai_debug) console.log ('AI PROCESS PAGEVIEW CHECKS');
2964
2965    ai_cookie = ai_load_cookie ();
2966
2967    document.querySelectorAll ('.ai-check-block').forEach ((element, i) => {
2968
2969      var block = element.dataset.aiBlock;
2970      var delay_pv = element.dataset.aiDelayPv;
2971      var every_pv = element.dataset.aiEveryPv;
2972
2973      var code_hash             = element.dataset.aiHash;
2974      var max_imp               = element.dataset.aiMaxImp;
2975      var limit_imp_per_time    = element.dataset.aiLimitImpPerTime;
2976      var limit_imp_time        = element.dataset.aiLimitImpTime;
2977      var max_clicks            = element.dataset.aiMaxClicks;
2978      var limit_clicks_per_time = element.dataset.aiLimitClicksPerTime;
2979      var limit_clicks_time     = element.dataset.aiLimitClicksTime;
2980
2981
2982      var global_limit_clicks_per_time = element.dataset.aiGlobalLimitClicksPerTime;
2983      var global_limit_clicks_time     = element.dataset.aiGlobalLimitClicksTime;
2984
2985      if (ai_debug) console.log ('AI CHECK INITIAL DATA, block:', block);
2986
2987      if (typeof delay_pv != 'undefined' && delay_pv > 0) {
2988        if (!ai_check_data.hasOwnProperty (block)) {
2989          ai_check_data [block] = {};
2990        }
2991        ai_check_data [block]['d'] = delay_pv;
2992
2993        var cookie_delay_pv = '';
2994        if (ai_cookie.hasOwnProperty (block)) {
2995          if (ai_cookie [block].hasOwnProperty ('d')) {
2996            cookie_delay_pv = ai_cookie [block]['d'];
2997          }
2998        }
2999
3000        if (cookie_delay_pv === '') {
3001          if (ai_debug) console.log ('AI CHECK PAGEVIEWS, block:', block, 'delay:', delay_pv);
3002
3003          ai_set_cookie (block, 'd', delay_pv - 1);
3004        }
3005      }
3006
3007      if (typeof every_pv != 'undefined' && every_pv >= 2) {
3008        if (!ai_check_data.hasOwnProperty (block)) {
3009          ai_check_data [block] = {};
3010        }
3011
3012        if (typeof ai_delay_showing_pageviews === 'undefined' && (!ai_cookie.hasOwnProperty (block) || !ai_cookie [block].hasOwnProperty ('d'))) {
3013          // Set d to process e
3014          if (!ai_cookie.hasOwnProperty (block)) {
3015            ai_cookie [block] = {};
3016          }
3017          ai_cookie [block]['d'] = 0;
3018        }
3019
3020        ai_check_data [block]['e'] = every_pv;
3021      }
3022
3023      if (typeof max_imp != 'undefined' && max_imp > 0) {
3024        if (!ai_check_data.hasOwnProperty (block)) {
3025          ai_check_data [block] = {};
3026        }
3027        ai_check_data [block]['i'] = max_imp;
3028        ai_check_data [block]['h'] = code_hash;
3029
3030        var cookie_code_hash = '';
3031        var cookie_max_imp = '';
3032        if (ai_cookie.hasOwnProperty (block)) {
3033          if (ai_cookie [block].hasOwnProperty ('i')) {
3034            cookie_max_imp = ai_cookie [block]['i'];
3035          }
3036          if (ai_cookie [block].hasOwnProperty ('h')) {
3037            cookie_code_hash = ai_cookie [block]['h'];
3038          }
3039        }
3040
3041        if (cookie_max_imp === '' || cookie_code_hash != code_hash) {
3042          if (ai_debug) console.log ('AI CHECK IMPRESSIONS, block:', block, 'max', max_imp, 'impressions', 'hash', code_hash);
3043
3044          ai_set_cookie (block, 'i', max_imp);
3045          ai_set_cookie (block, 'h', code_hash);
3046        }
3047      } else {
3048          if (ai_cookie.hasOwnProperty (block) && ai_cookie [block].hasOwnProperty ('i')) {
3049            if (ai_debug) console.log ('AI IMPRESSIONS, block', block, 'removing i');
3050
3051            ai_set_cookie (block, 'i', '');
3052            if (!ai_cookie [block].hasOwnProperty ('c') && !ai_cookie [block].hasOwnProperty ('x')) {
3053              ai_set_cookie (block, 'h', '');
3054            }
3055          }
3056        }
3057
3058      if (typeof limit_imp_per_time != 'undefined' && limit_imp_per_time > 0 && typeof limit_imp_time != 'undefined' && limit_imp_time > 0) {
3059        if (!ai_check_data.hasOwnProperty (block)) {
3060          ai_check_data [block] = {};
3061        }
3062        ai_check_data [block]['ipt'] = limit_imp_per_time;
3063        ai_check_data [block]['it']  = limit_imp_time;
3064
3065        var cookie_limit_imp_per_time = '';
3066        var cookie_limit_imp_time = '';
3067        if (ai_cookie.hasOwnProperty (block)) {
3068          if (ai_cookie [block].hasOwnProperty ('ipt')) {
3069            cookie_limit_imp_per_time = ai_cookie [block]['ipt'];
3070          }
3071          if (ai_cookie [block].hasOwnProperty ('it')) {
3072            cookie_limit_imp_time = ai_cookie [block]['it'];
3073          }
3074        }
3075
3076        if (cookie_limit_imp_per_time === '' || cookie_limit_imp_time === '') {
3077          if (ai_debug) console.log ('AI CHECK IMPRESSIONS, block:', block, 'max', limit_imp_per_time, 'impresssions per', limit_imp_time, 'days (' + (limit_imp_time * 24 * 3600), 's)');
3078
3079          ai_set_cookie (block, 'ipt', limit_imp_per_time);
3080
3081          var date = new Date();
3082          var timestamp = Math.round (date.getTime() / 1000);
3083
3084          ai_set_cookie (block, 'it', Math.round (timestamp + limit_imp_time * 24 * 3600));
3085        }
3086        if (cookie_limit_imp_time > 0) {
3087          var date = new Date();
3088          var timestamp = Math.round (date.getTime() / 1000);
3089
3090          if (cookie_limit_imp_time <= timestamp) {
3091            if (ai_debug) console.log ('AI CHECK IMPRESSIONS, block:', block, 'reset max', limit_imp_per_time, 'impresssions per', limit_imp_time, 'days (' + (limit_imp_time * 24 * 3600), 's)');
3092
3093            ai_set_cookie (block, 'ipt', limit_imp_per_time);
3094            ai_set_cookie (block, 'it', Math.round (timestamp + limit_imp_time * 24 * 3600));
3095          }
3096        }
3097      } else {
3098          if (ai_cookie.hasOwnProperty (block)) {
3099            if (ai_cookie [block].hasOwnProperty ('ipt')) ai_set_cookie (block, 'ipt', '');
3100            if (ai_cookie [block].hasOwnProperty ('it'))  ai_set_cookie (block, 'it',  '');
3101          }
3102        }
3103
3104      if (typeof max_clicks != 'undefined' && max_clicks > 0) {
3105        if (!ai_check_data.hasOwnProperty (block)) {
3106          ai_check_data [block] = {};
3107        }
3108        ai_check_data [block]['c'] = max_clicks;
3109        ai_check_data [block]['h'] = code_hash;
3110
3111        var cookie_code_hash = '';
3112        var cookie_max_clicks = '';
3113        if (ai_cookie.hasOwnProperty (block)) {
3114          if (ai_cookie [block].hasOwnProperty ('c')) {
3115            cookie_max_clicks = ai_cookie [block]['c'];
3116          }
3117          if (ai_cookie [block].hasOwnProperty ('h')) {
3118            cookie_code_hash = ai_cookie [block]['h'];
3119          }
3120        }
3121
3122        if (cookie_max_clicks === '' || cookie_code_hash != code_hash) {
3123          if (ai_debug) console.log ('AI CHECK CLICKS, block:', block, 'max', max_clicks, 'clicks', 'hash', code_hash);
3124
3125          ai_set_cookie (block, 'c', max_clicks);
3126          ai_set_cookie (block, 'h', code_hash);
3127        }
3128      } else {
3129          if (ai_cookie.hasOwnProperty (block) && ai_cookie [block].hasOwnProperty ('c')) {
3130            if (ai_debug) console.log ('AI CLICKS, block', block, 'removing c');
3131
3132            ai_set_cookie (block, 'c', '');
3133            if (!ai_cookie [block].hasOwnProperty ('i') && !ai_cookie [block].hasOwnProperty ('x')) {
3134              ai_set_cookie (block, 'h', '');
3135            }
3136          }
3137        }
3138
3139      if (typeof limit_clicks_per_time != 'undefined' && limit_clicks_per_time > 0 && typeof limit_clicks_time != 'undefined' && limit_clicks_time > 0) {
3140        if (!ai_check_data.hasOwnProperty (block)) {
3141          ai_check_data [block] = {};
3142        }
3143        ai_check_data [block]['cpt'] = limit_clicks_per_time;
3144        ai_check_data [block]['ct']  = limit_clicks_time;
3145
3146        var cookie_limit_clicks_per_time = '';
3147        var cookie_limit_clicks_time = '';
3148
3149        if (ai_cookie.hasOwnProperty (block)) {
3150          if (ai_cookie [block].hasOwnProperty ('cpt')) {
3151            cookie_limit_clicks_per_time = ai_cookie [block]['cpt'];
3152          }
3153          if (ai_cookie [block].hasOwnProperty ('ct')) {
3154            cookie_limit_clicks_time = ai_cookie [block]['ct'];
3155          }
3156        }
3157
3158        if (cookie_limit_clicks_per_time === '' || cookie_limit_clicks_time === '') {
3159          if (ai_debug) console.log ('AI CHECK CLICKS, block:', block, 'max', limit_clicks_per_time, 'clicks per', limit_clicks_time, 'days (' + (limit_clicks_time * 24 * 3600), 's)');
3160
3161          ai_set_cookie (block, 'cpt', limit_clicks_per_time);
3162
3163          var date = new Date();
3164          var timestamp = Math.round (date.getTime() / 1000);
3165
3166          ai_set_cookie (block, 'ct', Math.round (timestamp + limit_clicks_time * 24 * 3600));
3167        }
3168
3169        if (cookie_limit_clicks_time > 0) {
3170          var date = new Date();
3171          var timestamp = Math.round (date.getTime() / 1000);
3172
3173          if (cookie_limit_clicks_time <= timestamp) {
3174            if (ai_debug) console.log ('AI CHECK CLICKS, block:', block, 'reset max', limit_clicks_per_time, 'clicks per', limit_clicks_time, 'days (' + (limit_clicks_time * 24 * 3600), 's)');
3175
3176            ai_set_cookie (block, 'cpt', limit_clicks_per_time);
3177            ai_set_cookie (block, 'ct', Math.round (timestamp + limit_clicks_time * 24 * 3600));
3178          }
3179        }
3180      } else {
3181          if (ai_cookie.hasOwnProperty (block)) {
3182            if (ai_cookie [block].hasOwnProperty ('cpt')) ai_set_cookie (block, 'cpt', '');
3183            if (ai_cookie [block].hasOwnProperty ('ct'))  ai_set_cookie (block, 'ct', '');
3184          }
3185        }
3186
3187      if (typeof global_limit_clicks_per_time != 'undefined' && global_limit_clicks_per_time > 0 && typeof global_limit_clicks_time != 'undefined' && global_limit_clicks_time > 0) {
3188        if (!ai_check_data.hasOwnProperty ('G')) {
3189          ai_check_data ['G'] = {};
3190        }
3191        ai_check_data ['G']['cpt'] = global_limit_clicks_per_time;
3192        ai_check_data ['G']['ct']  = global_limit_clicks_time;
3193
3194        var global_cookie_limit_clicks_per_time = '';
3195        var global_cookie_limit_clicks_time = '';
3196
3197        if (ai_cookie.hasOwnProperty ('G')) {
3198          if (ai_cookie ['G'].hasOwnProperty ('cpt')) {
3199            global_cookie_limit_clicks_per_time = ai_cookie ['G']['cpt'];
3200          }
3201          if (ai_cookie ['G'].hasOwnProperty ('ct')) {
3202            global_cookie_limit_clicks_time = ai_cookie ['G']['ct'];
3203          }
3204        }
3205
3206        if (global_cookie_limit_clicks_per_time === '' || global_cookie_limit_clicks_time === '') {
3207          if (ai_debug) console.log ('AI CHECK CLICKS GLOBAL: max', global_limit_clicks_per_time, 'clicks per', global_limit_clicks_time, 'days (' + (global_limit_clicks_time * 24 * 3600), 's)');
3208
3209          ai_set_cookie ('G', 'cpt', global_limit_clicks_per_time);
3210
3211          var date = new Date();
3212          var timestamp = Math.round (date.getTime() / 1000);
3213
3214          ai_set_cookie ('G', 'ct', Math.round (timestamp + global_limit_clicks_time * 24 * 3600));
3215        }
3216
3217        if (global_cookie_limit_clicks_time > 0) {
3218          var date = new Date();
3219          var timestamp = Math.round (date.getTime() / 1000);
3220
3221          if (global_cookie_limit_clicks_time <= timestamp) {
3222            if (ai_debug) console.log ('AI CHECK CLICKS GLOBAL: reset max', global_limit_clicks_per_time, 'clicks per', global_limit_clicks_time, 'days (' + (global_limit_clicks_time * 24 * 3600), 's)');
3223
3224            ai_set_cookie ('G', 'cpt', global_limit_clicks_per_time);
3225            ai_set_cookie ('G', 'ct', Math.round (timestamp + global_limit_clicks_time * 24 * 3600));
3226          }
3227        }
3228      } else {
3229          if (ai_cookie.hasOwnProperty ('G')) {
3230            if (ai_cookie ['G'].hasOwnProperty ('cpt')) ai_set_cookie ('G', 'cpt', '');
3231            if (ai_cookie ['G'].hasOwnProperty ('ct'))  ai_set_cookie ('G', 'ct', '');
3232          }
3233        }
3234    });
3235
3236    // Remove check class so it's not processed again when tracking is called
3237    document.querySelectorAll ('.ai-check-block').forEach ((element, i) => {
3238      element.classList.remove ('ai-check-block');
3239    });
3240
3241
3242    if (ai_debug) console.log ('');
3243    if (ai_debug) console.log ('AI PROCESS CHECKS', ai_check_data);
3244
3245
3246    if (ai_debug) console.log ('AI CHECK PAGEVIEWS');
3247
3248    for (var cookie_block in ai_cookie) {
3249      for (var cookie_block_property in ai_cookie [cookie_block]) {
3250        if (cookie_block_property == 'd') {
3251          if (ai_debug) console.log ('AI CHECK PAGEVIEWS block:', cookie_block);
3252
3253          var delay = ai_cookie [cookie_block][cookie_block_property];
3254          if (delay > 0) {
3255            if (ai_debug) console.log ('AI PAGEVIEW, block', cookie_block, 'delayed for', delay - 1, 'pageviews');
3256
3257            ai_set_cookie (cookie_block, 'd', delay - 1);
3258          } else {
3259              if (ai_check_data.hasOwnProperty (cookie_block) && ai_check_data [cookie_block].hasOwnProperty ('e')) {
3260                if (ai_debug) console.log ('AI PAGEVIEW, block', cookie_block, 'show every', ai_check_data [cookie_block]['e'], 'pageviews, delayed for', ai_check_data [cookie_block]['e'] - 1, 'pageviews');
3261
3262                ai_set_cookie (cookie_block, 'd', ai_check_data [cookie_block]['e'] - 1);
3263              } else {
3264                  if (!ai_check_data.hasOwnProperty (cookie_block) || !ai_check_data [cookie_block].hasOwnProperty ('d')) {
3265                    if (ai_debug) console.log ('AI PAGEVIEW, block', cookie_block, 'removing d');
3266
3267                    ai_set_cookie (cookie_block, 'd', '');
3268                  }
3269                }
3270            }
3271        }
3272      }
3273    }
3274  }
3275
3276  function ai_log_impressions () {
3277
3278    var ai_debug = typeof ai_debugging !== 'undefined'; // 7
3279//    var ai_debug = false;
3280
3281    if (ai_debug) console.log ('');
3282    if (ai_debug) console.log ('AI TRACKING');
3283
3284    // Move to ai_process_impressions ()
3285//    Array.prototype.forEach.call (document.querySelectorAll ('[data-ai]'), function (block_wrapping_div) {
3286//      var new_tracking_data = '';
3287
3288//      if (ai_debug && block_wrapping_div.hasAttribute ('data-ai-1')) console.log ('AI TRACKING CHECKING BLOCK', block_wrapping_div.getAttribute ('class'));
3289
3290//      for (var fallback_level = 1; fallback_level <= 9; fallback_level ++) {
3291//        if (block_wrapping_div.hasAttribute ('data-ai-' + fallback_level)) {
3292//          new_tracking_data = block_wrapping_div.getAttribute ('data-ai-' + fallback_level);
3293
3294//          if (ai_debug) console.log ('  FALLBACK LEVEL', fallback_level);
3295//        } else break;
3296//      }
3297
3298//      if (new_tracking_data != '') {
3299//        block_wrapping_div.setAttribute ('data-ai', new_tracking_data);
3300//      }
3301
3302//      if (ai_debug) console.log ('  TRACKING DATA UPDATED TO', b64d (block_
3302wrapping_div.getAttribute ('data-ai')));
3303//    });
3304
3305    if (ai_track_pageviews) {
3306      var client_width = document.documentElement.clientWidth, inner_width =  window.innerWidth;
3307      var viewport_width = client_width < inner_width ? inner_width : client_width;
3308
3309      var version = 0;
3310      var name = '?';
3311      ai_viewport_widths.every ((width, index) => {
3312        if (viewport_width >= width) {
3313          version = ai_viewport_indexes [index];
3314          name = ai_viewport_names [index];
3315          return (false);
3316        }
3317        return (true);
3318      });
3319
3320      if (ai_debug) console.log ('AI TRACKING PAGEVIEW, viewport width:', viewport_width, '=>', name);
3321
3322      var ai_masking_data = document.querySelector (b64d ("Ym9keQ==")).getAttribute (b64d (ai_adb_attribute));
3323      if (typeof ai_masking_data === "string") {
3324        var ai_masking = ai_masking_data == b64d ("bWFzaw==");
3325      }
3326
3327      if (typeof ai_masking_data === "string" && typeof ai_masking === "boolean" && ai_masking) {
3328        if (ai_external_tracking) {
3329          external_tracking ("ad blocking", 0, ai_viewport_names [version - 1], 0, 0, '', true);
3330        }
3331        version |= 0x80;
3332      }
3333
3334      pageview_data = [0, version];
3335    }
3336
3337    ai_process_pageview_checks ();
3338
3339    ai_process_impressions ();
3340
3341    // Pageview data was not sent with block impressions
3342    if (pageview_data.length != 0) {
3343      if (ai_debug) console.log ('AI PROCESS IMPRESSIONS - SENDING PAGEVIEW DATA', pageview_data);
3344
3345      if (ai_internal_tracking) {
3346
3347        var url_data = {
3348          action: "ai_ajax",
3349          ai_check: ai_data_id,
3350        };
3351
3352        var formBody = [];
3353        for (var property in url_data) {
3354          var encodedKey = encodeURIComponent (property);
3355          var encodedValue = encodeURIComponent (url_data [property]);
3356          formBody.push (encodedKey + "=" + encodedValue);
3357        }
3358
3359        var encodedKey = encodeURIComponent ('views[]');
3360        var encodedValue = encodeURIComponent (0);
3361        formBody.push (encodedKey + "=" + encodedValue);
3362
3363        var encodedKey = encodeURIComponent ('versions[]');
3364        var encodedValue = encodeURIComponent (version);
3365        formBody.push (encodedKey + "=" + encodedValue);
3366
3367        formBody = formBody.join ("&");
3368
3369        async function ai_post_pageview () {
3370          const response = await fetch (ai_ajax_url, {
3371            method: 'POST',
3372            headers: {
3373              'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
3374            },
3375            body: formBody
3376          });
3377
3378          const text = await response.text ();
3379          return text;
3380        }
3381
3382        ai_post_pageview ().then (data => {
3383          if (ai_debug) {
3384            data = data.trim ();
3385            if (data != "") {
3386              var db_records = JSON.parse (data);
3387              console.log ("AI DB RECORDS: ", db_records);
3388            }
3389          }
3390        });
3391      }
3392    }
3393
3394    ai_tracking_finished = true;
3395  }
3396
3397  window.addEventListener ('load', (event) => {
3398    if (typeof ai_delay_tracking == 'undefined') {
3399      ai_delay_tracking = 0;
3400    }
3401
3402    setTimeout (ai_log_impressions, ai_delay_tracking + 1400);
3403    setTimeout (ai_install_click_trackers, ai_delay_tracking + 1500);
3404  });
3405}
3406
3407ai_ready (ai_tracking);
3408
3409}
3410
3411ai_js_code = true;
3412</script>
vendor: 1 bytes, line 3412
3412
3413<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":"16679d1d4c80462f983ccc1bc3a05352","r":1,"spa":2}' crossorigin="anonymous"></script>
3413
3414</body>
3415</html>
3416
3417<!-- Dynamic page generated in 0.306 seconds. -->
3418<!-- Cached page generated by WP-Super-Cache on 2026-09-24 12:30:15 -->
3419
3420<!-- Compression = gzip -->

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.