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&d=robohash&r=g","url":"https://secure.gravatar.com/avatar/ace25749c026e0e13e41c8d427699211a5edc7e78139caea021bbc11de81cc20?s=96&d=robohash&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 » Feed" href="https://the-gadgeteer.com/feed/" /> 49<link rel="alternate" type="application/rss+xml" title="The Gadgeteer » 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 » 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&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/">… 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/">… 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/">… 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’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/">… 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/">… 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/">… 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&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&media=https%3A%2F%2Fthe-gadgeteer.com%2Fwp-content%2Fuploads%2F2026%2F09%2FGoogleBook-OS-Cover.jpeg&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’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&#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'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&srk=ac6d22e265055dcc48478983c2e14eb8&sra=s&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’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&gl=US&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"> </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.