1/* PORTAL-10730: single browser runtime, shared by modern and legacy clients. */ 2(function (global) { 3 'use strict'; 4 if (global.PravovedAnalytics) return; 5 var prefix = 'pravoved_analytics_'; 6 var uuidPattern = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i; 7 var memory = {}; 8 var events = ('page_view cta_impression cta_click form_open form_interaction_start question_submitted ' + 9 'registration_shown registration_started registration_completed tariffs_shown tariff_selected ' + 10 'checkout_shown payment_started chat_milestone').split(' '); 11 var chatStages = ('chat_started clarification_requested clarification_received city_requested city_received ' + 12 'phone_requested phone_received consultation_preview_shown tariff_offer_shown payment_link_shown ' + 13 'full_consultation_shown consultation_ready').split(' '); 14 var stringFields = ('page_type surface component placement element_id form_id form_step stage status reason_code ' + 15 'split_version assignment_id scenario tariff_code').split(' '); 16 var numberFields = ['question_id', 'lead_id', 'order_id', 'element_version', 'interaction_no']; 17 function uuid() { 18 try { 19 if (global.crypto && global.crypto.randomUUID) return global.crypto.randomUUID(); 20 if (!global.crypto || !global.crypto.getRandomValues) return null; 21 var bytes = global.crypto.getRandomValues(new Uint8Array(16)); 22 bytes[6] = (bytes[6] & 15) | 64; 23 bytes[8] = (bytes[8] & 63) | 128; 24 var hex = Array.prototype.map.call(bytes, function (b) { return ('0' + b.toString(16)).slice(-2); }).join(''); 25 return hex.slice(0, 8) + '-' + hex.slice(8, 12) + '-' + hex.slice(12, 16) + '-' + hex.slice(16, 20) + '-' + hex.slice(20); 26 } catch (error) { return null; } 27 } 28 function read(kind, key) { 29 try { return global[kind].getItem(prefix + key); } catch (error) { return null; } 30 } 31 function write(kind, key, value) { 32 memory[key] = value; 33 try { global[kind].setItem(prefix + key, value); } catch (error) { /* volatile fallback */ } 34 } 35 function identity(key, kind) { 36 var value = read(kind, key) || memory[key]; 37 if (!uuidPattern.test(value || '')) { 38 value = uuid(); 39 if (value) write(kind, key, value); 40 } 41 memory[key] = value; 42 return value; 43 } 44 function context() { 45 return { visitor_id: identity('visitor_id', 'localStorage'), session_id: identity('session_id', 'sessionStorage'), journey_id: identity('journey_id', 'sessionStorage') }; 46 } 47 function renewJourney() { 48 var id = uuid(); 49 if (id) { write('sessionStorage', 'journey_id', id); write('sessionStorage', 'event_index', 0); write('sessionStorage', 'completed_journey_id', ''); } 50 return id; 51 } 52 function markJourneyComplete() { 53 var id = context().journey_id; 54 if (id) write('sessionStorage', 'completed_journey_id', id); 55 } 56 function beginNewQuestion() { 57 var current = context().journey_id; 58 var completed = read('sessionStorage', 'completed_journey_id') || memory.completed_journey_id; 59 return current && completed === current ? renewJourney() : current; 60 } 61 function dimension(value) { 62 return typeof value === 'number' && isFinite(value) && value >= 0 && value <= 65535 ? Math.round(value) : null; 63 } 64 function endpoint() { 65 var config = global.PravovedAnalyticsConfig || {}; 66 return typeof config.endpoint === 'string' && /^https:\/\//.test(config.endpoint) ? config.endpoint : ''; 67 } 68 function send(body, url, attempt) { 69 var retried = false; 70 function retry() { 71 if (!retried && attempt < 2) { 72 retried = true; 73 try { global.setTimeout(function () { send(body, url, attempt + 1); }, 500 * Math.pow(2, attempt)); } catch (error) { /* best effort */ } 74 } 75 } 76 try { 77 if (global.fetch) { 78 global.fetch(url, { method: 'POST', mode: 'cors', credentials: 'omit', keepalive: true, headers: { 'Content-Type': 'application/json' }, body: body }) 79 .then(function (response) { if (response.status >= 500 || response.status === 429) retry(); }, retry); 80 } else if (global.XMLHttpRequest) { 81 var xhr = new global.XMLHttpRequest(); 82 xhr.open('POST', url, true); 83 xhr.timeout = 2000; 84 xhr.setRequestHeader('Content-Type', 'application/json'); 85 xhr.onerror = retry; 86 xhr.ontimeout = retry; 87 xhr.onload = function () { if (xhr.status >= 500 || xhr.status === 429) retry(); }; 88 xhr.send(body); 89 } 90 } catch (error) { retry(); } 91 } 92 function captureSnapshot() { 93 var ids = context(); 94 var eventId = uuid(); 95 if (!eventId || !ids.visitor_id || !ids.journey_id || !ids.session_id) return null; 96 var index = Number(read('sessionStorage', 'event_index') || memory.event_index || 0); 97 if (!isFinite(index) || index < 0 || index >= 4294967295) index = 0; 98 write('sessionStorage', 'event_index', index + 1); 99 return { 100 ids: ids, 101 eventId: eventId, 102 index: index, 103 time: new Date().toISOString(), 104 pageUrl: String((global.location || {}).pathname || '').slice(0, 2048) 105 }; 106 } 107 function captureEvent() { 108 try { 109 if (!endpoint()) return null; 110 var snapshot = captureSnapshot(); 111 if (!snapshot) return null; 112 var sent = false;
113 return function (event, fields) { 114 if (sent) return null; 115 var id = track(event, fields, snapshot); 116 if (id) sent = true; 117 return id; 118 }; 119 } catch (error) { return null; } 120 } 121 function track(event, fields, captured) { 122 try { 123 fields = fields || {}; 124 var url = endpoint(); 125 if (!url || events.indexOf(event) === -1 || fields.split_id !== 'PORTAL-10682' || ['nosplit', 'a', 'b', 'c'].indexOf(fields.split_variant) === -1) return null; 126 if (event === 'chat_milestone' && chatStages.indexOf(fields.stage) === -1) return null; 127 var snapshot = captured || captureSnapshot(); 128 if (!snapshot) return null; 129 var ids = snapshot.ids, eventId = snapshot.eventId, index = snapshot.index; 130 var nav = global.navigator || {}, screen = global.screen || {}; 131 var payload = { 132 schema_version: 1, event_version: 1, event_id: eventId, dedup_key: eventId, event: event, source: 'frontend', 133 event_time: snapshot.time, event_index: index, visitor_id: ids.visitor_id, journey_id: ids.journey_id, session_id: ids.session_id, 134 split_id: 'PORTAL-10682', split_variant: fields.split_variant, 135 traffic_class: ['human', 'test', 'bot'].indexOf(fields.traffic_class) !== -1 ? fields.traffic_class : 'human', 136 page_url: snapshot.pageUrl, 137 user_agent: String(nav.userAgent || '').slice(0, 1024), language: String(nav.language || '').slice(0, 32), 138 timezone_offset_minutes: -new Date().getTimezoneOffset(), screen_width: dimension(screen.width), screen_height: dimension(screen.height), 139 viewport_width: dimension(global.innerWidth), viewport_height: dimension(global.innerHeight), 140 device_type: global.innerWidth < 768 ? 'mobile' : global.innerWidth < 1024 ? 'tablet' : 'desktop', 141 experiments_json: '{}', properties_json: '{}' 142 }; 143 var configuredUser = Number((global.PravovedAnalyticsConfig || {}).userId); 144 if (configuredUser > 0 && Math.floor(configuredUser) === configuredUser) payload.user_id = configuredUser; 145 try { 146 if (global.URL && global.document && global.document.referrer) payload.referrer_url = new global.URL(global.document.referrer).pathname.slice(0, 2048); 147 if (global.URL && global.location && global.location.href) { 148 var acquisition = new global.URL(global.location.href).searchParams; 149 ['utm_source', 'utm_medium', 'utm_campaign', 'utm_content', 'utm_term'].forEach(function (key) { 150 var value = acquisition.get(key); 151 if (value && /^[A-Za-z0-9_.-]{1,128}$/.test(value)) payload[key] = value; 152 }); 153 } 154 } catch (error) { /* omit malformed acquisition data */ } 155 stringFields.forEach(function (key) { 156 var value = fields[key]; 157 if (typeof value === 'string' && /^[a-zA-Z0-9_.:/-]{1,128}$/.test(value)) payload[key] = value; 158 }); 159 numberFields.forEach(function (key) { 160 var value = fields[key]; 161 if (typeof value === 'number' && isFinite(value) && Math.floor(value) === value && value > 0 && value <= 9007199254740991) payload[key] = value; 162 }); 163 if (event.indexOf('cta_') === 0 && (!payload.component || !payload.placement || !payload.element_id)) return null; 164 payload.element_version = payload.element_version || 1; 165 // Serialize exactly once: callers and transport retries cannot mutate the event. 166 send(JSON.stringify(payload), url, 0); 167 return eventId; 168 } catch (error) { return null; } 169 } 170 global.PravovedAnalytics = Object.freeze({ track: function (event, fields) { return track(event, fields); }, captureEvent: captureEvent, getContext: context, renewJourney: renewJourney, markJourneyComplete: markJourneyComplete, beginNewQuestion: beginNewQuestion }); 171})(window);
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.