PageSourceSearch

https://looke.com.br/scripts/session-replay.js?v=2026091110

js looke.com.br collected 2026-09-24 09:32:05 UTC 30,132 bytes, 923 lines download raw bytes

1/*
2 * Looke - Session Replay
3 *
4 * Loader unico para Microsoft Clarity e PostHog.
5 * A pagina recebe window.__lookeReplay pelo middleware.
6 */
7(function (w, d) {
8    'use strict';
9
10    if (w.SessionReplay) { return; }
11
12    var cfg = w.__lookeReplay || null;
13    if (!cfg || !cfg.enabled) { return; }
14
15    var ROLL_KEY = '__lk_sr_roll_v1';
16    var CONSENT_KEY = '__lk_sr_consent_v1';
17
18    var ready = { clarity: false, posthog: false };
19    var loaded = { clarity: false, posthog: false };
20    var pending = [];
21    var active = [];
22    var linked = false;
23    var started = false;
24    var posthogRecordingLimitTimer = null;
25
26    function log() {
27        if (!cfg.debug || !w.console || !w.console.log) { return; }
28        w.console.log.apply(w.console, ['[SessionReplay]'].concat([].slice.call(arguments)));
29    }
30
31    function storageGet(storage, key) {
32        try { return storage.getItem(key); } catch (e) { return null; }
33    }
34
35    function storageSet(storage, key, value) {
36        try { storage.setItem(key, value); } catch (e) { }
37    }
38
39    function hasConsent() {
40        if (!cfg.requireConsent) { return true; }
41
42        return storageGet(w.localStorage, CONSENT_KEY) === 'true';
43    }
44
45    function dice() {
46        var stored = storageGet(w.sessionStorage, ROLL_KEY);
47
48        if (stored === null) {
49            stored = String(Math.floor(Math.random() * 100));
50            storageSet(w.sessionStorage, ROLL_KEY, stored);
51        }
52
53        var parsed = parseInt(stored, 10);
54
55        if (isNaN(parsed) || parsed < 0 || parsed > 99) {
56            parsed = Math.floor(Math.random() * 100);
57            storageSet(w.sessionStorage, ROLL_KEY, String(parsed));
58        }
59
60        return parsed;
61    }
62
63    var roll = dice();
64
65    function sampled(rate) {
66        return typeof rate === 'number' && rate > 0 && roll < rate;
67    }
68
69    function selectorList(list) {
70        return list && list.length ? list.join(',') : null;
71    }
72
73    function addClass(node, className) {
74        if (!node || !className) { return; }
75
76        if (node.classList && node.classList.add) {
77            node.classList.add(className);
78            return;
79        }
80
81        var current = node.className || '';
82        if (typeof current === 'string' && (' ' + current + ' ').indexOf(' ' + className + ' ') < 0) {
83            node.className = current ? current + ' ' + className : className;
84        }
85    }
86
87    function safeQuerySelectorAll(selector) {
88        if (!selector) { return []; }
89
90        try {
91            return d.querySelectorAll(selector);
92        } catch (e) {
93            log('seletor invalido', selector, e);
94            return [];
95        }
96    }
97
98    function querySelectors(list) {
99        var result = [];
100
101        if (!list || !list.length) { return result; }
102
103        for (var i = 0; i < list.length; i++) {
104            var nodes = safeQuerySelectorAll(list[i]);
105
106            for (var j = 0; j < nodes.length; j++) {
107                result.push(nodes[j]);
108            }
109        }
110
111        return result;
112    }
113
114    function applyMaskAttributes() {
115        var maskNodes = querySelectors(cfg.maskSelectors);
116        for (var i = 0; i < maskNodes.length; i++) {
117            maskNodes[i].setAttribute('data-clarity-mask', 'True');
118            addClass(maskNodes[i], 'ph-mask');
119        }
120
121        var blockNodes = querySelectors(cfg.blockSelectors);
122        for (var j = 0; j < blockNodes.length; j++) {
123            blockNodes[j].setAttribute('data-clarity-mask', 'True');
124            addClass(blockNodes[j], 'ph-no-capture');
125        }
126    }
127
128    function watchDynamicDom() {
129        applyMaskAttributes();
130
131        if (d.readyState === 'loading') {
132            d.addEventListener('DOMContentLoaded', applyMaskAttributes);
133        }
134
135        try {
136            if (w.jQuery) {
137                w.jQuery(d).ajaxComplete(applyMaskAttributes);
138            }
139        } catch (e) { }
140
141        try {
142            var observer = new MutationObserver(function () {
143                applyMaskAttributes();
144            });
145
146            observer.observe(d.documentElement || d.body, {
147                childList: true,
148                subtree: true
149            });
150        } catch (e) { }
151    }
152
153    function normalizeKey(key) {
154        return String(key || '')
155            .replace(/([a-z0-9])([A-Z])/g, '$1_$2')
156            .toLowerCase()
157            .normalize('NFD')
158            .replace(/[\u0300-\u036f]/g, '');
159    }
160
161    function isSensitiveKey(key) {
162        var normalized = normalizeKey(key);
163
164        return /(^|[_\-.:\\/\s])(password|senha|pass|passwd|pwd|secret|token|document|documento|cpf|cnpj|card|cartao|cvv|security|email|e_mail|phone|telefone|celular|mobile|address|endereco|cep)($|[_\-.:\\/\s])/.test(normalized) ||
165            /credit[_\-.:\\/\s]*card|numero[_\-.:\\/\s]*cartao|cartao[_\-.:\\/\s]*credito|postal[_\-.:\\/\s]*code/.test(normalized);
166    }
167
168    function isPostHogInternalKey(key) {
169        if (!key) { return false; }
170
171        return key === 'token' ||
172            key === 'api_key' ||
173            key === 'distinct_id' ||
174            key === '$distinct_id' ||
175            key.charAt(0) === '$';
176    }
177
178    function sanitizeValue(key, value, options) {
179        var urlLike = /url|href|uri|link|referrer/i;
180        var preservePostHogInternals = !!(options && options.preservePostHogInternals);
181
182        if (key === '$set' || key === '$set_once') {
183            return sanitizeProperties(value);
184        }
185
186        if (urlLike.test(key || '') && typeof value === 'string') {
187            return sanitizeUrl(value);
188        }
189
190        if (preservePostHogInternals && isPostHogInternalKey(key)) {
191            return value;
192        }
193
194        if (isSensitiveKey(key)) {
195            return '[masked]';
196        }
197
198        if (Array.isArray(value)) {
199            return value.map(function (item) {
200                return sanitizeValue('', item, options);
201            });
202        }
203
204        if (value && typeof value === 'object') {
205            return sanitizeProperties(value, options);
206        }
207
208        return value;
209    }
210
211    function sanitizeProperties(props, options) {
212        if (!props || typeof props !== 'object') { return props; }
213
214        var clean = {};
215
216        for (var key in props) {
217            if (!Object.prototype.hasOwnProperty.call(props, key)) { continue; }
218
219            clean[key] = sanitizeValue(key, props[key], options);
220        }
221
222        return clean;
223    }
224
225    function sanitizeUrl(value) {
226        if (!value || typeof value !== 'string') { return value; }
227
228        try {
229            var url = new URL(value, w.location.origin);
230            url.search = '';
231            url.hash = '';
232            return url.toString();
233        } catch (e) {
234            return value.split('?')[0].split('#')[0];
235        }
236    }
237
238    function getPostHogMaxRecordingSeconds() {
239        var value = cfg.posthog ? cfg.posthog.maxRecordingSeconds : null;
240
241        if (value === null || value === undefined || value === '') { return 0; }
242
243        var seconds = parseInt(value, 10);
244
245        if (isNaN(seconds) || seconds <= 0) { return 0; }
246
247        return seconds;
248    }
249
250    function schedulePostHogRecordingLimit() {
251        var seconds = getPostHogMaxRecordingSeconds();
252
253        if (!seconds || !w.posthog || !w.posthog.stopSessionRecording) { return; }
254
255        if (posthogRecordingLimitTimer) {
256            w.clearTimeout(posthogRecordingLimitTimer);
257        }
258
259        posthogRecordingLimitTimer = w.setTimeout(function () {
260            try {
261                if (w.posthog && w.posthog.stopSessionRecording) {
262                    w.posthog.stopSessionRecording();
263                    log('posthog session replay pausado por limite de tempo', seconds);
264                }
265            } catch (e) {
266                log('posthog stopSessionRecording falhou', e);
267            }
268        }, seconds * 1000);
269    }
270
271    function roundSeconds(value) {
272        if (typeof value !== 'number' || !isFinite(value)) { return null; }
273
274        return Math.round(value * 100) / 100;
275    }
276
277    function getQueryParam(name) {
278        try {
279            return new URL(w.location.href).searchParams.get(name);
280        } catch (e) {
281            var match = w.location.search.match(new RegExp('[?&]' + name + '=([^&]+)'));
282            return match ? decodeURIComponent(match[1].replace(/\+/g, ' ')) : null;
283        }
284    }
285
286    function buildPlayerEventProps(video, extra) {
287        var currentSeconds = video ? roundSeconds(video.currentTime) : null;
288        var durationSeconds = video ? roundSeconds(video.duration) : null;
289        var percent = null;
290
291        if (currentSeconds !== null && durationSeconds && durationSeconds > 0) {
292            percent = Math.round((currentSeconds * 100 / durationSeconds) * 100) / 100;
293        }
294
295        var props = {
296            video_id: video && video.id ? video.id : null,
297            media_id: getQueryParam('m'),
298            current_seconds: currentSeconds,
299            duration_seconds: durationSeconds,
300            percent: percent,
301            current_url: sanitizeUrl(w.location.href)
302        };
303
304        extra = extra || {};
305
306        for (var key in extra) {
307            if (Object.prototype.hasOwnProperty.call(extra, key)) {
308                props[key] = extra[key];
309            }
310        }
311
312        return props;
313    }
314
315    function trackPlayerEvent(name, video, extra) {
316        try {
317            SessionReplay.track(name, buildPlayerEventProps(video, extra));
318        } catch (e) {
319            log('player event falhou', name, e);
320        }
321    }
322
323    function attachPlayerEventTracking(video) {
324        if (!video || video.__lookeSessionReplayPlayerEvents) { return; }
325
326        video.__lookeSessionReplayPlayerEvents = true;
327
328        var state = {
329            ready: false,
330            started: false,
331            ended: false,
332            errored: false,
333            buffering: false,
334            bufferingStartedAt: null,
335            milestones: {
336                25: false,
337                50: false,
338                75: false,
339                95: false
340            }
341        };
342
343        function markReady() {
344            if (state.ready) { return; }
345
346            state.ready = true;
347            trackPlayerEvent('looke_player_ready', video);
348        }
349
350        function markStarted() {
351            if (!state.started) {
352                state.started = true;
353                trackPlayerEvent('looke_player_started', video);
354            }
355
356            if (state.buffering) {
357                var elapsedSeconds = state.bufferingStartedAt ? roundSeconds((Date.now() - state.bufferingStartedAt) / 1000) : null;
358                state.buffering = false;
359                state.bufferingStartedAt = null;
360                trackPlayerEvent('looke_player_buffering_end', video, { buffering_seconds: elapsedSeconds });
361            }
362        }
363
364        function markBuffering() {
365            if (state.buffering || state.ended) { return; }
366
367            state.buffering = true;
368            state.bufferingStartedAt = Date.now();
369            trackPlayerEvent('looke_player_buffering_start', video);
370        }
371
372        function markProgress() {
373            var currentSeconds = roundSeconds(video.currentTime);
374            var durationSeconds = roundSeconds(video.duration);
375
376            if (currentSeconds === null || !durationSeconds || durationSeconds <= 0) { return; }
377
378            var percent = currentSeconds * 100 / durationSeconds;
379            var marks = [25, 50, 75, 95];
380
381            for (var i = 0; i < marks.length; i++) {
382                var mark = marks[i];
383
384                if (!state.milestones[mark] && percent >= mark) {
385                    state.milestones[mark] = true;
386                    trackPlayerEvent('looke_player_progress', video, { milestone: mark });
387                }
388            }
389        }
390
391        function markEnded() {
392            if (state.ended) { return; }
393
394            state.ended = true;
395            trackPlayerEvent('looke_player_ended', video);
396        }
397
398        function markError() {
399            // Video sem src (preview decorativa de pagina de detalhes) dispara
400            // error trivial; e um mesmo load com varios <source> dispara um error
401            // por source. Sem isto, o painel enche de looke_player_error repetido.
402            if (!video.currentSrc && !video.src) { return; }
403            if (state.errored) { return; }
404
405            state.errored = true;
406
407            var error = video.error || {};
408
409            trackPlayerEvent('looke_player_error', video, {
410                error_code: error.code || null
411            });
412        }
413
414        function resetErrorOnNewLoad() {
415            state.errored = false;
416        }
417
418        video.addEventListener('loadeddata', markReady);
419        video.addEventListener('loadedmetadata', markReady);
420        video.addEventListener('play', markStarted);
421        video.addEventListener('playing', markStarted);
422        video.addEventListener('waiting', markBuffering);
423        video.addEventListener('stalled', markBuffering);
424        video.addEventListener('timeupdate', markProgress);
425        video.addEventListener('seeked', function () {
426            trackPlayerEvent('looke_player_seeked', video);
427        });
428        video.addEventListener('ended', markEnded);
429        video.addEventListener('error', markError);
430        video.addEventListener('loadstart', resetErrorOnNewLoad);
431    }
432
433    function attachPlayerEventTrackingToPage() {
434        var videos = d.getElementsByTagName('video');
435
436        for (var i = 0; i < videos.length; i++) {
437            attachPlayerEventTracking(videos[i]);
438        }
439    }
440
441    function watchPlayerEvents() {
442        attachPlayerEventTrackingToPage();
443
444        if (d.readyState === 'loading') {
445            d.addEventListener('DOMContentLoaded', attachPlayerEventTrackingToPage);
446        }
447
448        try {
449            var observer = new MutationObserver(function () {
450                attachPlayerEventTrackingToPage();
451            });
452
453            observer.observe(d.documentElement || d.body, {
454                childList: true,
455                subtree: true
456            });
457        } catch (e) { }
458    }
459
460    var DRIVERS = {};
461
462    DRIVERS.clarity = {
463        name: 'clarity',
464
465        enabled: function () {
466            return !!(cfg.clarity && cfg.clarity.projectId && sampled(cfg.clarity.sampleRate));
467        },
468
469        load: function () {
470            if (loaded.clarity) { return; }
471            loaded.clarity = true;
472
473            (function (c, l, a, r, i, t, y) {
474                c[a] = c[a] || function () { (c[a].q = c[a].q || []).push(arguments); };
475                t = l.createElement(r);
476                t.async = 1;
477                t.src = 'https://www.clarity.ms/tag/' + encodeURIComponent(i);
478                y = l.getElementsByTagName(r)[0];
479                y.parentNode.insertBefore(t, y);
480            })(w, d, 'clarity', 'script', cfg.clarity.projectId);
481
482            ready.clarity = true;
483            log('clarity carregado');
484        },
485
486        identify: function (user) {
487            if (!user || !user.distinctId || !w.clarity) { return; }
488
489            w.clarity('identify', String(user.distinctId));
490
491            if (user.userId) { w.clarity('set', 'looke_user_id', String(user.userId)); }
492            if (user.profileId) { w.clarity('set', 'looke_profile_id', String(user.profileId)); }
493            if (user.planId) { w.clarity('set', 'looke_plan_id', String(user.planId)); }
494            if (user.rid) { w.clarity('set', 'looke_rid', String(user.rid)); }
495        },
496
497        track: function (name, props) {
498            if (!w.clarity) { return; }
499
500            w.clarity('event', String(name));
501
502            var clean = sanitizeProperties(props);
503            for (var key in clean) {
504                if (Object.prototype.hasOwnProperty.call(clean, key) && clean[key] !== null && clean[key] !== undefined) {
505                    w.clarity('set', String(key), String(clean[key]));
506                }
507            }
508        },
509
510        tag: function (key, value) {
511            if (w.clarity) {
512                w.clarity('set', String(key), String(value));
513            }
514        },
515
516        upgrade: function (reason) {
517            if (w.clarity) {
518                w.clarity('upgrade', String(reason || 'important'));
519            }
520        },
521
522        sessionUrl: function () {
523            try {
524                var match = d.cookie.match(/(?:^|;\s*)_clsk=([^;]+)/);
525                if (!match) { return null; }
526
527                var id = decodeURIComponent(match[1]).split('|')[0];
528                if (!id) { return null; }
529
530                return 'https://clarity.microsoft.com/projects/view/' + cfg.clarity.projectId +
531                    '/impressions?SessionId=' + encodeURIComponent(id);
532            } catch (e) {
533                return null;
534            }
535        }
536    };
537
538    DRIVERS.posthog = {
539        name: 'posthog',
540
541        enabled: function () {
542            return !!(cfg.posthog && cfg.posthog.apiKey && sampled(cfg.posthog.sampleRate));
543        },
544
545        load: function () {
546            if (loaded.posthog) { return; }
547            loaded.posthog = true;
548
549            try {
550                ensurePostHogBootstrap();
551                w.posthog.init(cfg.posthog.apiKey, buildPostHogOptions());
552            } catch (e) {
553                log('posthog init falhou', e);
554            }
555        },
556
557        identify: function (user) {
558            if (!user || !user.distinctId || !w.posthog) { return; }
559
560            w.posthog.identify(String(user.distinctId), {
561                looke_user_id: user.userId || null,
562                looke_profile_id: user.profileId || null,
563                looke_plan_id: user.planId || null,
564                looke_rid: user.rid || null
565            });
566        },
567
568        track: function (name, props) {
569            if (w.posthog) {
570                w.posthog.capture(String(name), sanitizeProperties(props) || {});
571            }
572        },
573
574        tag: function (key, value) {
575            if (!w.posthog) { return; }
576
577            var payload = {};
578            payload[key] = value;
579            w.posthog.register(sanitizeProperties(payload));
580        },
581
582        upgrade: function () {
583        },
584
585        sessionUrl: function () {
586            try {
587                return w.posthog && w.posthog.get_session_replay_url ? w.posthog.get_session_replay_url() : null;
588            } catch (e) {
589                return null;
590            }
591        }
592    };
593
594    function ensurePostHogBootstrap() {
595        if (w.posthog && w.posthog.__loaded) { return; }
596        if (w.posthog && w.posthog.__SV && typeof w.posthog.init === 'function') { return; }
597
598        var posthog = w.posthog || [];
599        var script = null;
600
601        function bind(target, method) {
602            var parts = method.split('.');
603            if (parts.length === 2) {
604                target = target[parts[0]];
605                method = parts[1];
606            }
607
608            target[method] = function () {
609                target.push([method].concat(Array.prototype.slice.call(arguments, 0)));
610            };
611        }
612
613        posthog._i = posthog._i || [];
614
615        posthog.init = function (apiKey, options, name) {
616            var instance = posthog;
617
618            if (!script) {
619                script = d.createElement('script');
620                script.type = 'text/javascript';
621                script.crossOrigin = 'anonymous';
622                script.async = true;
623                // Versao pinada: a 1.418.5 (19/08/2026) parou de gerar session no
624                // replay; a 1.418.4 era a versao que funcionava de manha. Sem o pin,
625                // /static/array.js entrega sempre o ultimo release deles.
626                script.src = resolvePostHogAssetHost(options) + '/static/1.418.4/array.js';
627                script.onerror = function () {
628                    script = null;
629                    log('posthog bloqueado ou indisponivel');
630                };
631
632                var firstScript = d.getElementsByTagName('script')[0];
633                firstScript.parentNode.insertBefore(script, firstScript);
634            }
635
636            if (typeof name !== 'undefined') {
637                instance = posthog[name] = [];
638            } else {
639                name = 'posthog';
640            }
641
642            instance.people = instance.people || [];
643            instance.toString = function (loaded) {
644                var label = 'posthog';
645                if (name !== 'posthog') { label += '.' + name; }
646                if (!loaded) { label += ' (stub)'; }
647                return label;
648            };
649            instance.people.toString = function () {
650                return instance.toString(1) + '.people (stub)';
651            };
652
653            var methods = 'capture identify setPersonProperties unsetPersonProperties group resetGroups setGroupPropertiesForFlags resetPersonPropertiesForFlags setGroupPropertiesForFlags reset resetGroups shutdown register register_once register_for_session unregister unregister_for_session getFeatureFlag getFeatureFlagPayload getFeatureFlagResult getAllFeatureFlags isFeatureEnabled reloadFeatureFlags updateFlags on onFeatureFlags onSessionId alias set_config startSessionRecording stopSessionRecording sessionRecordingStarted captureException captureLog get_property getSessionProperty get_distinct_id getGroups get_session_id get_session_replay_url opt_in_capturing opt_out_capturing has_opted_in_capturing has_opted_out_capturing get_explicit_consent_status is_capturing clear_opt_in_out_capturing debug'.split(' ');
654
655            for (var i = 0; i < methods.length; i++) {
656                bind(instance, methods[i]);
657            }
658
659            posthog._i.push([apiKey, options, name]);
660        };
661
662        posthog.__SV = 1;
663        w.posthog = posthog;
664    }
665
666    /*
667     * Host relativo ("/relay") vira absoluto na origem da propria pagina.
668     * E o modo de ligar o relay first-party sem fixar dominio na configuracao:
669     * o mesmo "/relay" vale para www.looke.com.br, homolog e localhost.
670     */
671    function resolveConfiguredHost(value) {
672        var host = String(value || '').replace(/\/$/, '');
673
674        if (host.charAt(0) === '/') {
675            return w.location.origin + host;
676        }
677
678        return host;
679    }
680
681    function resolvePostHogAssetHost(options) {
682        var configuredAssetHost = cfg.posthog && cfg.posthog.assetHost;
683        if (configuredAssetHost) {
684            return resolveConfiguredHost(configuredAssetHost);
685        }
686
687        var apiHost = options && options.api_host ? options.api_host : 'https://us.i.posthog.com';
688        return String(apiHost).replace('.i.posthog.com', '-assets.i.posthog.com').replace(/\/$/, '');
689    }
690
691    function buildPostHogOptions() {
692        // recordHeaders/recordBody fixados como falso: payload de rede fora da
693        // gravacao. O numero do cartao trafega no corpo dos POSTs de /Payment
694        // (GetCardPromotionIfAvailable e os formularios de assinatura/compra).
695        // No SDK, falso no cliente vence a configuracao remota do projeto.
696        var sessionRecording = {
697            maskAllInputs: true,
698            recordHeaders: false,
699            recordBody: false
700        };
701
702        var mask = selectorList(cfg.maskSelectors);
703        if (mask) { sessionRecording.maskTextSelector = mask; }
704
705        var block = selectorList(cfg.blockSelectors);
706        if (block) { sessionRecording.blockSelector = block; }
707
708        var apiHost = resolveConfiguredHost(cfg.posthog.host) || 'https://us.i.posthog.com';
709
710        var options = {
711            api_host: apiHost,
712            defaults: '2026-05-30',
713            debug: !!cfg.debug,
714            person_profiles: 'identified_only',
715            capture_pageview: true,
716            // Autocapture nao envia o texto do elemento clicado: titular e numero
717            // do cartao aparecem como texto puro nas telas de assinatura.
718            mask_all_text: true,
719            session_recording: sessionRecording,
720            before_send: function (event) {
721                if (!event) { return event; }
722
723                if (event.properties) { event.properties = sanitizeProperties(event.properties, { preservePostHogInternals: true }); }
724                if (event.$set) { event.$set = sanitizeProperties(event.$set); }
725                if (event.$set_once) { event.$set_once = sanitizeProperties(event.$set_once); }
726
727                if (event.properties && event.properties.$current_url) {
728                    event.properties.$current_url = sanitizeUrl(event.properties.$current_url);
729                }
730
731                if (event.properties && event.properties.$referrer) {
732                    event.properties.$referrer = sanitizeUrl(event.properties.$referrer);
733                }
734
735                return event;
736            },
737            loaded: function () {
738                ready.posthog = true;
739                log('posthog carregado');
740
741                try {
742                    if (w.posthog && w.posthog.capture) {
743                        w.posthog.capture('looke_session_replay_loaded', {
744                            provider: cfg.provider || null,
745                            clarity_enabled: !!(cfg.clarity && cfg.clarity.projectId),
746                            posthog_project_id: cfg.posthog ? cfg.posthog.projectId : null,
747                            current_url: sanitizeUrl(w.location.href)
748                        });
749                    }
750                } catch (e) {
751                    log('posthog evento de carregamento falhou', e);
752                }
753
754                try {
755                    if (w.posthog && w.posthog.startSessionRecording) {
756                        w.posthog.startSessionRecording();
757                        schedulePostHogRecordingLimit();
758                    }
759                } catch (e) {
760                    log('posthog startSessionRecording falhou', e);
761                }
762
763                drain();
764                crossLink();
765            }
766        };
767
768        // Atras do relay o api_host nao e mais *.posthog.com; o ui_host mantem
769        // os links de replay e o toolbar apontando para o painel de verdade.
770        if (apiHost.indexOf('.posthog.com') < 0) {
771            options.ui_host = 'https://us.posthog.com';
772        }
773
774        return options;
775    }
776
777    function isReady(driver) {
778        return ready[driver.name] === true;
779    }
780
781    function call(driver, method, args) {
782        try {
783            if (typeof driver[method] === 'function') {
784                driver[method].apply(driver, args);
785            }
786        } catch (e) {
787            log(method + ' falhou em ' + driver.name, e);
788        }
789    }
790
791    function dispatch(method, args) {
792        for (var i = 0; i < active.length; i++) {
793            var driver = active[i];
794
795            if (isReady(driver)) {
796                call(driver, method, args);
797            } else {
798                pending.push({ driver: driver.name, method: method, args: args });
799            }
800        }
801    }
802
803    function drain() {
804        var queued = pending;
805        pending = [];
806
807        for (var i = 0; i < queued.length; i++) {
808            var item = queued[i];
809            var driver = DRIVERS[item.driver];
810
811            if (driver && isReady(driver)) {
812                call(driver, item.method, item.args);
813            } else {
814                pending.push(item);
815            }
816        }
817    }
818
819    function crossLink() {
820        if (linked || !ready.clarity || !ready.posthog || !w.clarity || !w.posthog) { return; }
821
822        try {
823            var sessionId = w.posthog.get_session_id ? w.posthog.get_session_id() : null;
824            if (sessionId) { w.clarity('set', 'posthog_session_id', String(sessionId)); }
825
826            var replayUrl = DRIVERS.posthog.sessionUrl();
827            if (replayUrl) { w.clarity('set', 'posthog_replay_url', String(replayUrl)); }
828
829            w.posthog.register({ clarity_project_id: cfg.clarity ? cfg.clarity.projectId : null });
830
831            linked = true;
832        } catch (e) {
833            log('cross-link falhou', e);
834        }
835    }
836
837    function start() {
838        if (started) { return; }
839        if (!hasConsent()) {
840            log('aguardando consentimento');
841            return;
842        }
843
844        watchDynamicDom();
845        watchPlayerEvents();
846
847        for (var name in DRIVERS) {
848            if (Object.prototype.hasOwnProperty.call(DRIVERS, name) && DRIVERS[name].enabled()) {
849                active.push(DRIVERS[name]);
850            }
851        }
852
853        if (!active.length) {
854            log('nenhum provider selecionado no sorteio', roll);
855            started = true;
856            return;
857        }
858
859        started = true;
860
861        for (var i = 0; i < active.length; i++) {
862            call(active[i], 'load', []);
863        }
864
865        if (cfg.user && cfg.user.distinctId) {
866            SessionReplay.identify(cfg.user);
867        }
868
869        drain();
870        crossLink();
871    }
872
873    var SessionReplay = {
874        identify: function (user) {
875            dispatch('identify', [user || cfg.user]);
876        },
877
878        track: function (name, props) {
879            dispatch('track', [name, props]);
880        },
881
882        tag: function (key, value) {
883            dispatch('tag', [key, value]);
884        },
885
886        upgrade: function (reason) {
887            dispatch('upgrade', [reason]);
888        },
889
890        startAfterConsent: function () {
891            storageSet(w.localStorage, CONSENT_KEY, 'true');
892            start();
893        },
894
895        status: function () {
896            return {
897                roll: roll,
898                started: started,
899                requireConsent: !!cfg.requireConsent,
900                hasConsent: hasConsent(),
901                posthogMaxRecordingSeconds: getPostHogMaxRecordingSeconds(),
902                clarity: ready.clarity,
903                posthog: ready.posthog
904            };
905        },
906
907        getSessionUrls: function () {
908            var urls = {};
909
910            for (var i = 0; i < active.length; i++) {
911                if (isReady(active[i])) {
912                    urls[active[i].name] = active[i].sessionUrl();
913                }
914            }
915
916            return urls;
917        }
918    };
919
920    w.SessionReplay = SessionReplay;
921
922    start();
923})(window, document);

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.