PageSourceSearch

https://dostepnyswiat.pl/wp-content/plugins/full-picture-analytics…/public/common/fupi-helpers.js?ver=8.4.0

js dostepnyswiat.pl collected 2026-10-06 12:37:40 UTC 24,560 bytes, 692 lines download raw bytes

1(function (FP) {
2
3    'use strict';
4
5    var d = document,
6        w = window;
7
8    // We set some basic vars
9    FP.v = {};
10    fp.track_queue = [];
11    fpdata.activity = { total : 0, last : 0, current : 0 };
12    fpdata.refreshed = false;
13    
14    if ( document.referrer == document.location.origin + document.location.pathname ) {
15        fpdata.refreshed = true;
16    } else {
17        if ( performance.navigation ? performance.navigation.type === performance.navigation.TYPE_RELOAD : performance.getEntriesByType('navigation')[0].type === 'reload' ) fpdata.refreshed = true; // deprecated method first, the new one later
18    }
19
20    // fires function every X ms with an option to fire them ADDITIONALLY on start ("leading") and after events ("trailing")
21    FP.throttle = function (func, wait, options) {
22        var context, args, result;
23        var timeout = null;
24        var previous = 0;
25        if (!options) options = {};
26
27        var later = function later() {
28            previous = options.leading === false ? 0 : Date.now();
29            timeout = null;
30            result = func.apply(context, args);
31            if (!timeout) context = args = null;
32        };
33
34        return function () {
35            var now = Date.now();
36            if (!previous && options.leading === false) previous = now;
37            var remaining = wait - (now - previous);
38            context = this;
39            args = arguments;
40
41            if (remaining <= 0 || remaining > wait) {
42                if (timeout) {
43                    clearTimeout(timeout);
44                    timeout = null;
45                }
46
47                previous = now;
48                result = func.apply(context, args);
49                if (!timeout) context = args = null;
50            } else if (!timeout && options.trailing !== false) {
51                timeout = setTimeout(later, remaining);
52            }
53
54            return result;
55        };
56    };
57
58    FP.isObjectEmpty = function (obj) {
59        return obj.constructor === Object && Object.keys(obj).length === 0;
60    };
61
62    FP.isNumeric = function (n) {
63        return !isNaN(parseFloat(n)) && isFinite(n);
64    };
65
66    FP.reduce = function( arr ){
67        return arr.reduce( function(accumulator, val){ return val ? accumulator + val : accumulator } );
68    };
69
70    FP.remove = el => { if (el) el.parentNode.removeChild(el); };
71
72    FP.findFirst = (e, c) => {
73        if ( c === null ) return null;
74        if ( !e ) return false;
75        c = c || document;
76        return c.querySelector(e);
77    };
78
79    FP.addAction = function( action_name, fn ){
80
81        let arr = Array.isArray(action_name) ? action_name : [action_name]; // make sure that trigger is in an array
82
83        arr.forEach(function ( name , i) { 
84            if ( ! fp.actions[name] ) fp.actions[name] = [];
85            fp.actions[name].push( fn );
86        });
87    }
88
89    FP.doActions = ( action_name, args_o = null, cb ) => {
90        if ( fp.actions[action_name] ) fp.actions[action_name].forEach( fn => {
91            let return_val = fn( args_o );
92            if ( typeof return_val !== 'undefined' ) args_o = return_val;
93        } );
94        if ( cb ) cb( args_o );
95        // TODO: add in this place a function that sends the collected payload to server
96    }
97
98    FP.hasActions = action_name => {
99        return fp.actions[action_name] && fp.actions[action_name].length > 0;
100    };
101
102    function shouldCustomScriptLoadHere( geo ){
103
104        let geo_method = geo[0],
105            geo_countries = geo[1];
106
107        if ( fp.geo && geo_method && geo_countries ) { // we check fp.geo to prevent situations when user disabled geo but didn't save new tools settings
108        
109            if ( fp.ready ) {
110                return geo_method == 'incl' ? geo_countries.includes( fpdata.country ) : ! geo_countries.includes( fpdata.country );
111            }
112            return false;
113        }
114
115        return true;
116    }
117
118    function shouldScriptLoadHere( id ){
119
120        if ( fp.geo && fp[id].limit_country ) { // we check fp.geo to prevent situations when user disabled geo but didn't save new tools settings
121            
122            if ( fp.ready ) {
123
124                if ( fp[id].limit_country.method == 'excl' ) {
125                    return ! fp[id].limit_country.countries.includes( fpdata.country );
126                } else {
127                    return fp[id].limit_country.countries.includes( fpdata.country );
128                }
129            }
130
131            return false;
132        }
133
134        return true;
135    };
136
137    FP.isAllowedToLoad_basic = function( id, force_load, permissions_a, geo_a ){
138    
139        // STOP if we don't have all the basic data yet
140        if ( ! fp.ready ) return false;
141
142        // STOP if the script has already loaded
143        if ( fp.loaded.includes(id) ) return false;
144
145        // START if the load is forced
146        if ( force_load ) return true;
147
148        // STOP if the tab is not in focus AND we are NOT on WooCommerce checkout page
149        if ( fpdata.page_type !== 'Woo Order Received' ) {
150            if ( document.hidden ) return false;
151        }
152
153        // STOP tracking an excluded visitor (MUST be after checking FORCE LOAD)
154        if ( ! fp.vars.track_current_user ) return false;
155
156        // STOP if the script is set NOT to load in the current location
157        if ( geo_a && ! shouldCustomScriptLoadHere( geo_a ) ) return false;
158
159        // STOP if any permissions need to be given in this location...
160        if ( fp.notice.enabled && fp.notice.mode == 'optin' && ! fpdata.cookies && permissions_a.length > 0 ) return false;
161
162        // STOP if required permissions are not given
163        if ( fpdata.cookies && permissions_a.length > 0 ) {
164            if ( ! permissions_a.every( permission => fpdata.cookies[permission] ) ) return false;
165        }
166
167        return true;
168    };
169
170    FP.isAllowedToLoad = function( module_id, permissions_a, required_a, nr, tool_does_not_use_cookies = false ) {
171
172        var id = nr ? module_id + nr : module_id;
173
174        // STOP if we don't have all the basic data yet
175        if ( ! fp.ready ) return false;
176
177        // STOP if we have no settings for this tool
178        if ( ! fp[id] ) return false;
179
180        // STOP if the script has already loaded
181        if ( fp.loaded.includes(id) ) return false;
182
183        // STOP if the required data is missing
184        if ( required_a.some( req => ! fp[id][req] ) ) return false;
185
186        // START if the load is forced
187        if ( fp[id].force_load ) return true;
188
189        // STOP if the tab is not in focus AND we are NOT on WooCommerce checkout page
190        if ( fpdata.page_type !== 'Woo Order Received' ) {
191            if ( document.hidden ) return false;
192        }
193
194        // STOP tracking an excluded visitor (MUST be after checking FORCE LOAD)
195        if ( ! fp.vars.track_current_user ) return false;
196
197        // STOP if the script is set NOT to load in the current location
198        if ( ! shouldScriptLoadHere( id ) ) return false;
199
200        // START 
201        // if the tool doesn't use cookies
202        // or if it is set to disregard cookie choices
203        if ( tool_does_not_use_cookies || fp[id].disreg_cookies ) return true;
204
205        // STOP if we wait for consent but some permissions need to be given
206        if ( fp.notice.enabled && fp.notice.mode == 'optin' && ! fpdata.cookies && permissions_a.length > 0) return false;
207
208        // STOP if user chose their cookie preferences but some required permissions are missing
209        if ( fp.notice.enabled && fpdata.cookies && permissions_a.length > 0 ) {
210            if ( ! permissions_a.every( permission => fpdata.cookies[permission] ) ) return false;
211        }
212
213        return true;
214    };
215
216    FP.updateScrollValues = function(){
217
218        fpdata.scrolled = fpdata.scrolled || {};
219
220        fpdata.scrolled.current         = Math.round( d.documentElement.scrollTop / ( d.documentElement.scrollHeight - d.documentElement.clientHeight ) * 100 ) || 0;
221        fpdata.scrolled.current_px      = d.documentElement.scrollTop || 0;
222        fpdata.scrolled.max             = fpdata.scrolled.max || fpdata.scrolled.current;
223        fpdata.scrolled.max_px          = fpdata.scrolled.max_px || fpdata.scrolled.current_px;
224
225        if ( fpdata.scrolled.current > fpdata.scrolled.max ) {
226			fpdata.scrolled.max         = fpdata.scrolled.current;
227			fpdata.scrolled.max_px      = fpdata.scrolled.current_px;
228		}
229	}
230
231    FP.startActivityTimer = function () {
232
233        fpdata.activity.last = 0;
234
235        if (!FP.v.activityTimerRunning) {
236            FP.v.activityTimerRunning = true;
237            FP.v.activityTimer = setInterval(function () {
238
239                fpdata.activity.total++;
240                fpdata.activity.current++;
241                fpdata.activity.last++;
242
243                FP.doActions( 'active_time_tick' );
244
245                if ( fpdata.activity.last >= 15 ) FP.stopActivityTimer(); // stop timer after 15 secs from last activity
246            }, 1000);
247        }
248    };
249
250    FP.stopActivityTimer = function () {
251        if (FP.v.activityTimerRunning) {
252            FP.v.activityTimerRunning = false;
253            clearInterval(FP.v.activityTimer);
254        }
255    };
256
257    FP.encode = function (string) {
258        return window.btoa(string).split('=').join('')
259    }
260
261    FP.detectAddedElement = callback => {
262
263		const observer = new MutationObserver( mutations => {
264		  	mutations.forEach( mutation => {
265				if ( mutation.type === 'childList' ) {
266			  		callback( mutation.addedNodes );
267				}
268		  	} );
269		} );
270	  
271		observer.observe( document.body, {
272			childList: true,
273			subtree: true
274		} );
275	}
276
277    FP.initCondTracking = ( events_settings, cb ) => {
278		
279		if ( ! ( events_settings && fp.atrig ) ) return;
280		if ( ! fp.atrig.actions ) fp.atrig.actions = {};
281
282		events_settings.forEach( e => {
283			
284			if ( ! fp.atrig.actions[e.atrig_id] ) fp.atrig.actions[e.atrig_id] = [];
285			
286			fp.atrig.actions[e.atrig_id].push( {
287				'func' : cb.bind( this, e ),
288				'repeat' : e.repeat
289			} );
290		});
291	}
292
293    /* V8 mods - START */
294
295    // Check if WPFP can use cookies
296
297    function check_if_can_save_wpfp_cookies( first_check = false ) {
298
299        // save previous state
300        let prev_check = !! fp.vars.can_save_wpfp_cookies; // "!!" changes undefined into false
301        
302        // get current state
303        fp.vars.can_save_wpfp_cookies = ! fp.notice.enabled || fp.notice.mode == 'notify' || fp.notice.mode == 'hide' || ( fp.notice.mode == 'optout' && ! fpdata.cookies ) || ( fp.notice.mode == 'optin' && fpdata.cookies && fpdata.cookies.stats );
304
305        // check if the state has changed
306        fp.vars.consents_changed = first_check ? false : prev_check != fp.vars.can_save_wpfp_cookies;        
307    }
308
309    check_if_can_save_wpfp_cookies( true );
310
311    // Get session data from cookies
312
313    function get_session_data_from_cookies(){
314
315        let session_cookie = FP.readCookie('fp_current_session');
316        if ( session_cookie ) fpdata.current_session = JSON.parse(session_cookie);
317
318        
319    }
320
321    get_session_data_from_cookies();
322
323    
324
325    function create_new_single_session_data(){
326        
327        fpdata.current_session = {};
328
329        
330
331        FP.setCookie( 'fp_current_session', JSON.stringify(fpdata.current_session), 0, 30 ); // 30 mins
332    }
333
334    function update_single_session_data(){
335        if ( ! fpdata.current_session ) return;
336        
337        FP.setCookie( 'fp_current_session', JSON.stringify(fpdata.current_session), 0, 30 ); // 30 mins
338    }
339
340    
341
342    // Set or update session data when the page loads
343    function set_session_data(){
344        
345        if ( fp.vars.can_save_wpfp_cookies ) {
346            
347            fpdata.new_session = ! fpdata.current_session;
348            
349            ! fpdata.current_session ? create_new_single_session_data() : update_single_session_data();
350            
351
352        } else {
353            fpdata.new_session = ! fpdata.refreshed && ! window.sessionStorage['fp_old_session'] && ( window.history.length == 1 || ( window.history.length == 2 && ! document.referrer ) );
354        }
355
356        fpdata.new_tab = ! fpdata.new_session && ! window.sessionStorage['fp_old_session'];
357        window.sessionStorage['fp_old_session'] = true; // removed on a new tab
358    };
359
360    set_session_data();
361
362    // CREATE, UPDATE OR REMOVE SESSION DATA
363    // triggered after users change cookie preferences or when a page gains focus
364
365    FP.updateSessionData = () => {
366        
367        check_if_can_save_wpfp_cookies();
368
369        if ( fp.vars.consents_changed ) {
370            
371            // if we can no longer use session cookies
372            if ( ! fp.vars.can_save_wpfp_cookies ) {
373                
374                // delete everything
375                FP.deleteCookie( 'fp_current_session' );
376                delete fpdata.current_session;
377                
378            
379            // if we can now use session cookies
380            } else {
381
382                // get latest sesion data (in case user agreed to cookies on a different tab)
383                get_session_data_from_cookies();
384
385                // set new data if it wasn\'t set before (when a user has just chosen sth in the banner)
386                ! fpdata.current_session ? create_new_single_session_data() : update_single_session_data();
387                
388            };
389
390        } else {
391            // get latest sesion data (in case user visited a different tab before opening this one)
392            get_session_data_from_cookies();
393        }
394    }
395
396    /* V8 mods - END */
397
398    FP.isClickTarget = function( selector ){
399		return ( ! fpdata.clicked.link && ! fpdata.clicked.middle && fpdata.clicked.element.matches( selector ) ) || ( fpdata.clicked.link && fpdata.clicked.link.element.matches( selector ) );
400	}
401    
402    // the difference between this Fn and isAnchorLinkToCurrentPage is that this one doesn't check if the link actually works
403    function isLinkToCurrentPage (link) {
404        let target_url_obj = new URL( link.href );
405        return target_url_obj.origin + target_url_obj.pathname == location.origin + location.pathname;
406    }
407	
408	// checks if the link is an anchor to an EXISTING element on the same page
409	function isAnchorLinkToCurrentPage (link){
410        
411        let url = new URL( link.href ),
412            el = false;
413        
414        try {
415            el = FP.findFirst( url.hash );
416        } catch (e) {
417            el = false;
418        }
419        
420        return !! el;
421    };
422
423	function isOutboundLink (el) {
424        return el.href.indexOf(location.host) == -1 && el.href.indexOf('mailto:') != 0 && el.href.indexOf('tel:') != 0 && el.href.indexOf('http') == 0;
425    };
426
427	function trackClicks(e, is_middle_click) {
428
429		let redirect_stopped = false;
430
431		if ( e.target.classList.contains('fupi_click_stopped') ) return;
432		
433		// PREVENT MULTI CLICKS
434	    // Do not run this function if a visitor clicks the element multiple times in a short time-span
435	    var now = Date.now();
436	    if ( ! ( ! FP.v.lastClick || now - FP.v.lastClick > fp.vars.dblclck_time ) ) return;
437	    FP.v.lastClick = now;
438		
439		// PREVENT REDIRECTS
440
441		// prevent default if a visitor clicked a link that is to be opened on the current tab
442		var link_el = e.target.closest('a[href]');
443
444		if ( link_el && ! is_middle_click && link_el.target != '_blank' && fp.vars.link_click_delay  ){
445			e.preventDefault(); // prevents redirects
446			e.stopPropagation(); // prevents other event listeners from firing
447			e.target.classList.add('fupi_click_stopped');
448			e.target.style.pointerEvents = 'none';
449			redirect_stopped = true;
450			if ( fp.vars.debug ) console.log('[FP] link-click stopped');
451		};
452
453		// GET CLICK DATA
454
455		fpdata.clicked = {
456			'element' : e.target,
457			'middle' : is_middle_click,
458		};
459
460		if ( link_el && link_el.href.length > 1 ) {
461
462			fpdata.clicked.link 				= {};
463			fpdata.clicked.link.element			= link_el;
464			fpdata.clicked.link.href			= link_el.href;
465			fpdata.clicked.link.is_to_current_page = isLinkToCurrentPage(link_el);
466			fpdata.clicked.link.target_blank 	= link_el.target == '_blank';
467
468			fpdata.clicked.link.is_outbound 	= isOutboundLink(link_el);
469			fpdata.clicked.link.is_anchor 		= isAnchorLinkToCurrentPage(link_el);
470
471            if ( link_el.href.includes('mailto:') ){
472                fpdata.clicked.link.is_email = true;
473                fpdata.clicked.link.safe_email = link_el.href.replace('mailto:', '').split('@')[0];
474            }
475
476            if ( link_el.href.includes('tel:') ){
477                fpdata.clicked.link.is_tel = true;
478                fpdata.clicked.link.safe_tel = link_el.href.replace('tel:','').slice(-5);
479            }
480		}
481
482		// RUN QUEUED FNs
483
484		FP.doActions( 
485			'click', 
486			false, // no slug
487			() => { // cb after all functions are run
488				if ( fpdata.clicked.element.classList.contains('fupi_click_stopped') && typeof fpdata.clicked.element.click == 'function' ) {
489					fpdata.clicked.element.click();
490					fpdata.clicked.element.classList.remove('fupi_click_stopped');
491					e.target.style.pointerEvents = '';
492					if ( fp.vars.debug ) console.log('[FP] Initiated click event after all FP functions');
493				}
494			}
495		);
496    };
497
498    function getAttributesFromStr(str){
499
500        let clean_str = str.replaceAll( "\'", "'").replaceAll('\"', '"'),
501            parts = clean_str.trim().split(' '), // spaces occur in unexpected places!
502			ok_parts = parts.filter( v => v ), // remove empty values
503			ret_val = {};
504
505		for ( var i = 0; i < ok_parts.length; i++ ) {
506
507			let part = ok_parts[i],
508				eq_index = part.indexOf('='),
509				last_char = part[part.length-1];
510
511			// if we have an equal sign
512			// (this means that the value before the equal sign is the key and the one after is the value)
513			if ( eq_index != -1 ){
514
515				// we check if the last element of the current part is an apostrophe. If it isn\'t then it means we split the value in two or more pieces and need to join it with the next string parts
516				while ( ! ( last_char == '"' || last_char == "'" ) && i+1 <= ok_parts.length ) {
517					part += ' ' + ok_parts[i+1];
518					last_char = part[part.length-1];
519					i++;
520				}
521
522				// if we have the key and the whole value
523				if ( last_char == '"' || last_char == "'" ) {
524
525					// split on the first occurance of "=" sign
526					let key_val = part.split(/=(.*)/s); 
527                    
528                    // remove empties
529                    key_val = key_val.filter( v => v );
530                    
531                    // remove apostrophes
532                    if ( key_val[1].includes('"') ){
533                        key_val[1] = key_val[1].replaceAll('"', '');
534                    };
535
536                    if ( key_val[1].includes("'") ){
537                        key_val[1] = key_val[1].replaceAll("'", '');
538                    } ; 
539
540                    // save in an array
541					ret_val[key_val[0]] = key_val[1];
542				}
543
544			// if we don't have an equal sign this is a single value
545			} else {
546				ret_val[part] = true;
547			}
548		};
549
550		return ret_val;
551    };
552
553    // Add blocked scripts to HTML
554    function addScriptsToDOM() {
555
556        fp.blocked_scripts.forEach( scr_data => {
557
558            let url = scr_data[0],
559                attr_s = scr_data[1],
560                scr_id = scr_data[2],
561                force_load = scr_data[3],
562                permissions_a = scr_data[4],
563                geo_a = scr_data[5],
564                type = scr_data[6] || false;
565
566			if ( FP.isAllowedToLoad_basic( scr_id, force_load, permissions_a, geo_a ) ) {
567			    if ( ! url && attr_s == 'empty' ){
568                    FP.loadScript( scr_id );
569                } else {
570                    let attr_o = getAttributesFromStr(attr_s);
571                    FP.getScript( url, ()=>{fp.loaded.push( scr_id ) }, attr_o, type );        
572                }
573            }
574		} )
575	}
576
577    // FIRE TAGS WHEN THE DOCUMENT GETS AND LOSES FOCUS
578
579    function doPageShowActions(){
580
581        if ( ! fp.vars.page_show_tracked ){
582
583            fp.vars.page_show_tracked = true;
584            fp.vars.page_hide_tracked = false;
585
586            fpdata.doc_in_focus = true;
587            
588            FP.startActivityTimer();
589            
590            var cookies = FP.readCookie('fp_cookie');
591            fpdata.cookies = cookies ? JSON.parse(cookies) : false;
592
593            FP.updateConsents();
594            
595            FP.updateSessionData();
596
597            FP.sendEvt( 'fp_load_scripts' );
598
599            if ( fp.actions.page_in_focus ) FP.doActions('page_in_focus');
600        }
601    }
602
603    function doPageHideActions(){
604        if ( ! fp.vars.page_hide_tracked ) {
605            fp.vars.page_hide_tracked = true;
606            fp.vars.page_show_tracked = false;
607
608            fpdata.doc_in_focus = false;
609            FP.stopActivityTimer();
610            if ( fp.actions.close ) FP.doActions('page_in_blur');
611            fpdata.activity.current = 0;
612        }
613    }
614
615    // ON DYNAMIC URL CHANGES
616    // URL is set every second with setInterval() and not "active_time_tick", to make the check even when the page is not in focus
617
618	let currentUrl = location.href;
619	  
620	setInterval( () => { 
621		if ( location.href !== currentUrl ) {
622			currentUrl = location.href;
623			FP.doActions( 'url_change' );
624		}
625	}, 1000);
626
627    // pagehide/show fires on some events but is cross-browser
628    // !! it fires BEFORE visibilitychanges
629    // !! when the pageshow event fires the document obj doesn't have updated cookies or localStarage yet, thus we don't use it for "show"
630    window.addEventListener( "pagehide", e => { doPageHideActions() }, false );
631    // window.addEventListener( "pageshow", e => { doPageShowActions('pageshow') }, false ); visibilitychange is universal
632
633    // beforeunload doesn't work with prev/next page buttons and has problems on mobiles
634    window.addEventListener( "beforeunload", e => { doPageHideActions() }, false );
635
636    // visibilitychanges fires on all events but has problems on mobiles and in safari
637    // !! fires AFTER pagehide/show
638    // !! when the visibilitychange event fires for "show" the document obj already has updated cookies and localStarage
639    document.addEventListener( 'visibilitychange', function () {
640        document.hidden ? doPageHideActions() :  doPageShowActions('visibilitychange');
641        //if ( fp.page_visibility ) FP.doActions( 'page_visibility' );
642    }, false);
643
644    // load custom/extra scripts to DOM
645    document.addEventListener( 'fp_load_scripts', addScriptsToDOM );
646
647    function formSubmitEvents( {target} ){
648        fpdata.submitted_form = { 'element' : target };
649		FP.doActions( 'form_submit' );
650    }
651
652    // ON DOM LOADED
653	document.addEventListener( 'DOMContentLoaded', ()=>{
654
655        // fp.vars.dom_loaded_time = Date.now();
656        addScriptsToDOM();
657
658        // init actions waiting for DOM loaded
659        setTimeout ( ()=>{ FP.doActions( ['dom_loaded'] ) }, 250 ); // we must add a small delay to make sure that all triggers are hooked
660
661        // start listening to form submits
662        setTimeout( ()=>{ document.addEventListener('submit', formSubmitEvents ) }, fp.vars.formsubm_trackdelay ? fp.vars.formsubm_trackdelay * 1000 : 1000 );
663        
664        // start listening to DOM modifications
665		if ( fp.vars.use_mutation_observer ) FP.detectAddedElement( addedNodes => {
666            let els = FP.nl2Arr( addedNodes );
667            if ( els.length > 0 ) FP.doActions( ['dom_modified'], els );
668        } );
669	});
670
671
672    // ON MOUSE MOVE FOR USER ACTVITY TRACKER
673    document.addEventListener( 'mousemove', FP.throttle( FP.startActivityTimer, 500 ) ); // This starts the user's activity timer
674
675    if ( ! document.hidden) {
676        FP.startActivityTimer();
677        fpdata.doc_in_focus = true;
678        fp.vars.page_show_tracked = true;
679        fp.vars.page_hide_tracked = false;
680    };
681
682    // ON LEFT CLICK
683	window.addEventListener( 'click', function (e) {
684		if ( fp.actions.click ) trackClicks(e, false);
685	}, true);
686
687	// ON MIDDLE CLICK
688	window.addEventListener( 'mouseup', function(e) {
689		if ( fp.actions.click && e.button == 1) trackClicks(e, true);
690	});
691
692})(FP);

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.