PageSourceSearch

https://www.i-life-u.com/wp-content/plugins/google-analytics-dashb…/assets/js/frontend.js?ver=1791069765

js i-life-u.com collected 2026-10-03 23:22:58 UTC 23,297 bytes, 643 lines download raw bytes

1/**
2 * Developer's Notice:
3 *
4 * Note: JS in this file (and this file itself) is not garunteed backwards compatibility. JS can be added, changed or removed at any time without notice.
5 * For more information see the `Backwards Compatibility Guidelines for Developers` section of the README.md file.
6 */
7/**
8 * Handles:
9 * - JS Events handling
10 *
11 * @since 6.0.12
12 */
13var ExactMetrics = function(){
14	/* ExactMetrics JS  events tracking works on all major browsers, including IE starting at IE 7, via polyfills for any major JS function used that
15	   is not supported by at least  95% of the global and/or US browser marketshare. Currently, IE 7 & 8 which as of 2/14/17 have under 0.25% global marketshare, require
16	   us to polyfill Array.prototype.lastIndexOf, and if they continue to drop, we might remove this polyfill at some point. In that case note that events tracking
17	   for IE 7/8 will continue to work, with the exception of events tracking of downloads. */
18	var lastClicked  = [];
19	var internalAsOutboundCategory = '';
20
21	this.setLastClicked = function(valuesArray,fieldsArray,tracked){
22		valuesArray = typeof valuesArray !== 'undefined' ? valuesArray : [];
23		fieldsArray = typeof fieldsArray !== 'undefined' ? fieldsArray : [];
24		tracked     = typeof tracked !== 'undefined' ? tracked : false;
25
26		lastClicked.valuesArray = valuesArray;
27		lastClicked.fieldsArray = fieldsArray;
28	};
29
30	this.getLastClicked = function () {
31		return lastClicked;
32	};
33
34	this.setInternalAsOutboundCategory = function( category ){
35		internalAsOutboundCategory = category;
36	};
37
38	this.getInternalAsOutboundCategory = function () {
39		return internalAsOutboundCategory;
40	};
41
42	this.sendEvent = function ( fieldsArray ) {
43		__gaTrackerSend( [], fieldsArray );
44	};
45
46	function __gaTrackerIsDebug () {
47		if ( window.exactmetrics_debug_mode ) {
48			 return true;
49		} else {
50			return false;
51		}
52	}
53
54	function __gaTrackerSend ( valuesArray, fieldsArray ) {
55		valuesArray = typeof valuesArray !== 'undefined' ? valuesArray : [];
56		fieldsArray = typeof fieldsArray !== 'undefined' ? fieldsArray : {};
57
58		__gaTracker( 'send', fieldsArray );
59
60		lastClicked.valuesArray = valuesArray;
61		lastClicked.fieldsArray = fieldsArray;
62		lastClicked.tracked     = true;
63		__gaTrackerLog( 'Tracked: ' + valuesArray.type );
64		__gaTrackerLog( lastClicked );
65	}
66
67	function __gaTrackerNotSend ( valuesArray ) {
68		valuesArray             = typeof valuesArray !== 'undefined' ? valuesArray : [];
69
70		lastClicked.valuesArray = valuesArray;
71		lastClicked.fieldsArray = [];
72		lastClicked.tracked     = false;
73		__gaTrackerLog( 'Not Tracked: ' + valuesArray.exit );
74		__gaTrackerLog( lastClicked );
75	}
76
77	function __gaTrackerLog ( message ) {
78		if ( __gaTrackerIsDebug() ) {
79			console.dir( message );
80		}
81	}
82
83	function __gaTrackerStringTrim( x ) {
84		return x.replace(/^\s+|\s+$/gm,'');
85	}
86
87	function __gaTrackerGetDomain() {
88	   var i=0,currentdomain=document.domain,p=currentdomain.split('.'),s='_gd'+(new Date()).getTime();
89	   while(i<(p.length-1) && document.cookie.indexOf(s+'='+s)==-1){
90		  currentdomain = p.slice(-1-(++i)).join('.');
91		  document.cookie = s+"="+s+";domain="+currentdomain+";";
92	   }
93	   document.cookie = s+"=;expires=Thu, 01 Jan 1970 00:00:01 GMT;domain="+currentdomain+";";
94	   return currentdomain;
95	}
96
97	function __gaTrackerGetExtension( extension ) {
98		extension = extension.toString();
99		extension = extension.substring( 0, (extension.indexOf( "#" ) == -1 ) ? extension.length : extension.indexOf( "#" ) ); /* Remove the anchor at the end, if there is one */
100		extension = extension.substring( 0, (extension.indexOf( "?" ) == -1 ) ? extension.length : extension.indexOf( "?" ) ); /* Remove the query after the file name, if there is one */
101		extension = extension.substring( extension.lastIndexOf( "/" ) + 1, extension.length ); /* Remove everything before the last slash in the path */
102		if ( extension.length > 0 && extension.indexOf('.') !== -1 ) { /* If there's a period left in the URL, then there's a extension. Else it is not a extension. */
103			extension = extension.substring( extension.indexOf( "." ) + 1 ); /* Remove everything but what's after the first period */
104			return extension;
105		} else {
106			return "";
107		}
108	}
109
110	function __gaTrackerLoaded() {
111		return typeof(__gaTracker) !== 'undefined' && __gaTracker && __gaTracker.hasOwnProperty( "loaded" ) && __gaTracker.loaded == true; /* jshint ignore:line */
112	}
113
114	function __gaTrackerTrackedClick( event ) {
115		return event.which == 1 || event.which == 2 || event.metaKey || event.ctrlKey || event.shiftKey || event.altKey;
116	}
117
118	function __gaTrackerGetDownloadExtensions() {
119		var download_extensions = [];
120		if ( typeof exactmetrics_frontend.download_extensions == 'string' ) {
121			download_extensions = exactmetrics_frontend.download_extensions.split(",");
122		}
123		return download_extensions;
124	}
125
126	function __gaTrackerGetInboundPaths() {
127		var inbound_paths = [];
128		if ( typeof exactmetrics_frontend.inbound_paths == 'string' ) {
129			inbound_paths = JSON.parse( exactmetrics_frontend.inbound_paths );
130		}
131
132		return inbound_paths;
133	}
134
135	function __gaTrackerTrackedClickType( event ) {
136		if ( event.which == 1 ) {
137			return 'event.which=1';
138		} else if ( event.which == 2 ) {
139			return 'event.which=2';
140		} else if (  event.metaKey ){
141			return 'metaKey';
142		} else if (  event.ctrlKey ) {
143			return 'ctrlKey';
144		} else if ( event.shiftKey ) {
145			return 'shiftKey';
146		} else if (  event.altKey ) {
147			return 'altKey';
148		} else {
149			return '';
150		}
151	}
152
153	function __gaTrackerLinkType( el ) {
154		var download_extensions = __gaTrackerGetDownloadExtensions();
155		var inbound_paths       = __gaTrackerGetInboundPaths();
156		var type                = 'unknown';
157		var link 				= el.href;
158		var extension           = __gaTrackerGetExtension( el.href );
159		var currentdomain       = __gaTrackerGetDomain();
160		var hostname            = el.hostname;
161		var protocol            = el.protocol;
162		var pathname       		= el.pathname;
163		link 					= link.toString();
164		var index, len;
165		var category 			=  el.getAttribute("data-vars-ga-category");
166
167		if ( category ) {
168			return category;
169		}
170
171		if ( link.match( /^javascript\:/i ) ) {
172			type = 'internal'; /* if it's a JS link, it's internal */
173		} else if ( protocol && protocol.length > 0 && ( __gaTrackerStringTrim( protocol ) == 'tel' || __gaTrackerStringTrim( protocol ) == 'tel:' ) ) { /* If it's a telephone link */
174			type = "tel";
175		} else if ( protocol && protocol.length > 0 && ( __gaTrackerStringTrim( protocol ) == 'mailto' ||  __gaTrackerStringTrim( protocol ) == 'mailto:' ) ) { /* If it's a email */
176			type = "mailto";
177		} else if ( hostname && currentdomain && hostname.length > 0 && currentdomain.length > 0 && ! hostname.endsWith( '.' + currentdomain)  && hostname !== currentdomain ) { /* If it's a outbound */
178			type = "external";
179		}
179 else if ( pathname && JSON.stringify( inbound_paths ) != "{}" && pathname.length > 0 ) { /* If it's an internal as outbound */
180			var inbound_paths_length = inbound_paths.length;
181			for ( var inbound_paths_index = 0; inbound_paths_index < inbound_paths_length; inbound_paths_index ++ ) {
182				if ( inbound_paths[ inbound_paths_index ].path && inbound_paths[ inbound_paths_index ].label && inbound_paths[ inbound_paths_index ].path.length > 0 && inbound_paths[ inbound_paths_index ].label.length > 0 && pathname.startsWith( inbound_paths[ inbound_paths_index ].path ) ) {
183					type         				= "internal-as-outbound";
184					internalAsOutboundCategory  = "outbound-link-" + inbound_paths[ inbound_paths_index ].label;
185					break;
186				}
187			}
188		/* Enable window.exactmetrics_experimental_mode at your own risk. We might eventually remove it. Also you may/can/will burn through GA quota for your property quickly. */
189		} else if ( hostname && window.exactmetrics_experimental_mode && hostname.length > 0 && document.domain.length > 0 && hostname !== document.domain ) { /* If it's a cross-hostname link */
190			type = "cross-hostname";
191		}
192
193		if ( extension && ( type === 'unknown' || 'external' === type ) && download_extensions.length > 0 && extension.length > 0 ) { /* If it's a download */
194			for ( index = 0, len = download_extensions.length; index < len; ++index ) {
195				if ( download_extensions[ index ].length > 0 && ( link.endsWith( download_extensions[ index ] ) || download_extensions[ index ]  == extension ) ) {
196					type = "download";
197					break;
198				}
199			}
200		}
201
202		if ( type === 'unknown' ) {
203			type = 'internal';
204		}
205		return type;
206	}
207
208	function __gaTrackerLinkTarget( el, event ) {
209
210		/* Is actual target set and not _(self|parent|top)? */
211		var target = ( el.target && !el.target.match( /^_(self|parent|top)$/i ) ) ? el.target : false;
212
213		/* Assume a target if Ctrl|shift|meta-click */
214		if ( event.ctrlKey || event.shiftKey || event.metaKey || event.which == 2 ) {
215			target = "_blank";
216		}
217		return target;
218	}
219
220	function __gaTrackerGetTitle( el ) {
221		if ( el.getAttribute("data-vars-ga-label") && el.getAttribute("data-vars-ga-label").replace(/\n/ig, '') ) {
222			return el.getAttribute("data-vars-ga-label").replace(/\n/ig, '');
223		} else if ( el.title && el.title.replace(/\n/ig, '') ) {
224			return el.title.replace(/\n/ig, '');
225		} else if ( el.innerText && el.innerText.replace(/\n/ig, '') ) {
226			return el.innerText.replace(/\n/ig, '');
227		} else if ( el.getAttribute('aria-label') && el.getAttribute('aria-label').replace(/\n/ig, '') ) {
228			return el.getAttribute('aria-label').replace(/\n/ig, '');
229		} else if ( el.alt && el.alt.replace(/\n/ig, '') ) {
230			return el.alt.replace(/\n/ig, '');
231		} else if ( el.textContent && el.textContent.replace(/\n/ig, '') ) {
232			return el.textContent.replace(/\n/ig, '');
233		} else {
234			return undefined;
235		}
236	}
237
238	function __gaTrackerGetInnerTitle( el ) {
239		var children = el.children;
240		var count    = 0;
241		var child;
242		var value;
243		for (var i = 0; i < children.length; i++) {
244		  child = children[i];
245		  value = __gaTrackerGetTitle( child );
246		  if ( value ) {
247		     return value;
248		  }
249		  /* max search 100 elements to ensure performance */
250		  if ( count == 99 ) {
251		  	return undefined;
252		  }
253		  count++;
254		}
255		return undefined;
256	}
257
258	function __gaTrackerClickEvent( event ) {
259		var el            = event.srcElement || event.target;
260		var valuesArray   = [];
261		var fieldsArray;
262
263		/* Start Values Array */
264		valuesArray.el         = el;
265		valuesArray.ga_loaded  = __gaTrackerLoaded();
266		valuesArray.click_type = __gaTrackerTrackedClickType( event );
267
268		/* If GA is blocked or not loaded, or not main|middle|touch click then don't track */
269		if ( ! __gaTrackerLoaded() || ! __gaTrackerTrackedClick( event ) ) {
270			valuesArray.exit = 'loaded';
271			__gaTrackerNotSend( valuesArray );
272			return;
273		}
274
275		/* Loop up the DOM tree through parent elements if clicked element is not a link (eg: an image inside a link) */
276		while ( el && (typeof el.tagName == 'undefined' || el.tagName.toLowerCase() != 'a' || ! el.href ) ) {
277			el = el.parentNode;
278		}
279
280		/* if a link with valid href has been clicked */
281		if ( el && el.href && ! el.hasAttribute('xlink:href') ) {
282			var link                		= el.href;														/* What link are we tracking */
283			var extension           		= __gaTrackerGetExtension( el.href );							/* What extension is this link */
284			var download_extensions 		= __gaTrackerGetDownloadExtensions(); 							/* Let's get the extensions to track */
285			var inbound_paths       		= __gaTrackerGetInboundPaths(); 								/* Let's get the internal paths to track */
286			var home_url            		= exactmetrics_frontend.home_url; 							/* Let's get the url to compare for external/internal use */
287			var currentdomain       		= __gaTrackerGetDomain();										/* What domain are we on? */
288			var type                		= __gaTrackerLinkType( el ); 									/* What type of link is this? */
289			var target 						= __gaTrackerLinkTarget( el, event );							/* Is a new tab/window being opened? */
290			var action 						= el.getAttribute("data-vars-ga-action");
291			var label 						= el.getAttribute("data-vars-ga-label");
292
293			/* Element */
294			valuesArray.el                  = el;					/* el is an a element so we can parse it */
295			valuesArray.el_href             = el.href; 				/* "http://example.com:3000/pathname/?search=test#hash" */
296			valuesArray.el_protocol         = el.protocol; 			/* "http:" */
297			valuesArray.el_hostname         = el.hostname; 			/* "example.com" */
298			valuesArray.el_port             = el.port; 				/* "3000" */
299			valuesArray.el_pathname         = el.pathname; 			/* "/pathname/" */
300			valuesArray.el_search           = el.search; 			/* "?search=test" */
301			valuesArray.el_hash             = el.hash;				/* "#hash" */
302			valuesArray.el_host             = el.host; 				/* "example.com:3000" */
303
304			/* Settings */
305			valuesArray.debug_mode          = __gaTrackerIsDebug(); /* "example.com:3000" */
306			valuesArray.download_extensions = download_extensions;  /* Let's get the extensions to track */
307			valuesArray.inbound_paths       = inbound_paths; 		/* Let's get the internal paths to track */
308			valuesArray.home_url            = home_url;				/* Let's get the url to compare for external/internal use */
309
310			/* Parsed/Logic */
311			valuesArray.link                = link; 				/* What link are we tracking */
312			valuesArray.extension           = extension; 			/* What extension is this link */
313			valuesArray.type                = type; 				/* What type of link is this */
314			valuesArray.target              = target;				/* Is a new tab/window being opened? */
315			valuesArray.title 				= __gaTrackerGetTitle( el ); /* Try link title, then text content */
316
317			/* only find innerTitle if we need one */
318			if ( ! valuesArray.label && ! valuesArray.title ) {
319				valuesArray.title = __gaTrackerGetInnerTitle( el );
320			}
321
322			/* Let's track everything but internals (that aren't internal-as-externals) and javascript */
323			if ( type !== 'internal' && type !== 'javascript' ) {
324
325				var __gaTrackerHitBackRun = false; /* Tracker has not yet run */
326
327				/* HitCallback to open link in same window after tracker */
328				var __gaTrackerHitBack = function() {
329					/* Run the hitback only once */
330					if ( __gaTrackerHitBackRun ){
331						return;
332					}
333					__gaTrackerHitBackRun = true;
334					window.location.href = link;
335				};
336
337				var __gaTrackerNoRedirectExternal = function() {
338					valuesArray.exit = 'external';
339					__gaTrackerNotSend( valuesArray );
340				};
341
342				var __gaTrackerNoRedirectInboundAsExternal = function() {
343					valuesArray.exit = 'internal-as-outbound';
344					__gaTrackerNotSend( valuesArray );
345				};
346				var __gaTrackerNoRedirectCrossHostname = function() {
347					valuesArray.exit = 'cross-hostname';
348					__gaTrackerNotSend( valuesArray );
349				};
350
351				if ( target || type == 'mailto' || type == 'tel' ) { /* If target opens a new window then just track */
352					if ( type == 'download' ) {
353						fieldsArray = {
354							hitType       : 'event',
355							eventCategory : 'download',
356							eventAction   : action || link,
357							eventLabel    : label  || valuesArray.title,
358						};
359
360						__gaTrackerSend( valuesArray, fieldsArray );
361					} else if ( type == 'tel' ) {
362						fieldsArray = {
363							hitType       : 'event',
364							eventCategory : 'tel',
365							eventAction   : action || link,
366							eventLabel    : label  || valuesArray.title.replace('tel:', ''),
367						};
368
369						__gaTrackerSend( valuesArray, fieldsArray );
370					} else if ( type == 'mailto' ) {
371						fieldsArray = {
372							hitType       : 'event',
373							eventCategory : 'mailto',
374							eventAction   : action || link,
375							eventLabel    : label  || valuesArray.title.replace('mailto:', ''),
376						};
377
378						__gaTrackerSend( valuesArray, fieldsArray );
379					} else if ( type == 'internal-as-outbound' ) {
380						fieldsArray = {
381							hitType       : 'event',
382							eventCategory : internalAsOutboundCategory,
383							eventAction   : action || link,
384							eventLabel    : label  || valuesArray.title,
385						};
386
387						__gaTrackerSend( valuesArray, fieldsArray );
388					} else if ( type == 'external' ) {
389						fieldsArray = {
390							hitType: 'event',
391							eventCategory:'outbound-link',
392							eventAction: action || link,
393							eventLabel:  label  || valuesArray.title,
394						};
395
396						__gaTrackerSend( valuesArray, fieldsArray );
397					} else if ( type == 'cross-hostname' ) {
398						fieldsArray = {
399							hitType: 'event',
400							eventCategory:'cross-hostname',
401							eventAction: action || link,
402							eventLabel:  label  || valuesArray.title,
403						};
404
405						__gaTrackerSend( valuesArray, fieldsArray );
406					} else {
407						if ( type && type != 'internal' ) {
408							fieldsArray = {
409								hitType: 'event',
410								eventCategory: type,
411								eventAction:   action || link,
412								eventLabel:    label  || valuesArray.title,
413							};
414
415							__gaTrackerSend( valuesArray, fieldsArray );
416						} else {
417							valuesArray.exit = 'type';
418							__gaTrackerNotSend( valuesArray );
419						}
420					}
421				} else {
422					/* Prevent standard click, track then open */
423					if ( type != 'cross-hostname' && type != 'external' && type != 'internal-as-outbound' ) {
424						if (! event.defaultPrevented ) {
425							if ( event.preventDefault ) {
426								event.preventDefault();
427							} else {
428								event.returnValue = false;
429							}
430						}
431					}
432
433					if ( type == 'download' ) {
434						fieldsArray = {
435							hitType       : 'event',
436							eventCategory : 'download',
437							eventAction   : action || link,
438							eventLabel    : label  || valuesArray.title,
439							hitCallback   : __gaTrackerHitBack,
440						};
441
442						__gaTrackerSend( valuesArray, fieldsArray );
443					} else if ( type == 'internal-as-outbound' ) {
444						window.onbeforeunload = function(e) {
445							if (! event.defaultPrevented ) {
446								if ( event.preventDefault ) {
447									event.preventDefault();
448								} else {
449									event.returnValue = false;
450								}
451							}
452
453							fieldsArray = {
454								hitType       : 'event',
455								eventCategory : internalAsOutboundCategory,
456								eventAction   : action || link,
457								eventLabel    : label  || valuesArray.title,
458								hitCallback   : __gaTrackerHitBack,
459							};
460
461							if ( navigator.sendBeacon ) {
462								fieldsArray.transport = 'beacon';
463							}
464
465							__gaTrackerSend( valuesArray, fieldsArray );
466							setTimeout( __gaTrackerHitBack, 1000 );
467						};
468					} else if ( type == 'external' ) {
469						window.onbeforeunload = function(e) {
470							if (! event.defaultPrevented ) {
471								if ( event.preventDefault ) {
472									event.preventDefault();
473								} else {
474									event.returnValue = false;
475								}
476							}
477
478							fieldsArray = {
479								hitType       : 'event',
480								eventCategory : 'outbound-link',
481								eventAction   : action || link,
482								eventLabel    : label  || valuesArray.title,
483								hitCallback   : __gaTrackerHitBack,
484							};
485
486							if ( navigator.sendBeacon ) {
487								fieldsArray.transport = 'beacon';
488							}
489
490							__gaTrackerSend( valuesArray, fieldsArray );
491							setTimeout( __gaTrackerHitBack, 1000 );
492						};
493					} else if ( type == 'cross-hostname' ) {
494						window.onbeforeunload = function(e) {
495							if (! event.defaultPrevented ) {
496								if ( event.preventDefault ) {
497									event.preventDefault();
498								} else {
499									event.returnValue = false;
500								}
501							}
502
503							fieldsArray = {
504								hitType       : 'event',
505								eventCategory : 'cross-hostname',
506								eventAction   : action || link,
507								eventLabel    : label  || valuesArray.title,
508								hitCallback   : __gaTrackerHitBack,
509							};
510
511							if ( navigator.sendBeacon ) {
512								fieldsArray.transport = 'beacon';
513							}
514
515							__gaTrackerSend( valuesArray, fieldsArray );
516							setTimeout( __gaTrackerHitBack, 1000 );
517						};
518					} else {
519						if ( type && type !== 'internal' ) {
520							fieldsArray = {
521								hitType: 'event',
522								eventCategory: type,
523								eventAction:   action || link,
524								eventLabel:    label  || valuesArray.title,
525								hitCallback   : __gaTrackerHitBack,
526							};
527
528							__gaTrackerSend( valuesArray, fieldsArray );
529						} else {
530							valuesArray.exit = 'type';
531							__gaTrackerNotSend( valuesArray );
532						}
533					}
534
535					if ( type != 'external' && type != 'cross-hostname' && type != 'internal-as-outbound' ) {
536						/* Run hitCallback again if GA takes longer than 1 second */
537						setTimeout( __gaTrackerHitBack, 1000 );
538					} else {
539						if ( type == 'external' ) {
540							setTimeout( __gaTrackerNoRedirectExternal, 1100 );
541						} else if ( type == 'cross-hostname' ) {
542							setTimeout( __gaTrackerNoRedirectCrossHostname, 1100 );
543						} else {
544							setTimeout( __gaTrackerNoRedirectInboundAsExternal, 1100 );
545						}
546					}
547				}
548			} else {
549				valuesArray.exit = 'internal';
550				__gaTrackerNotSend( valuesArray );
551			}
552		} else {
553			valuesArray.exit = 'notlink';
554			__gaTrackerNotSend( valuesArray );
555		}
556	}
557	var prevHash = window.location.hash;
558	function __gaTrackerHashChangeEvent() {
559		/* Todo: Ready this section for JS unit testing */
560		if ( exactmetrics_frontend.hash_tracking === "true" && prevHash != window.location.hash ) {
561			prevHash = window.location.hash;
562			__gaTracker('set', 'page', location.pathname + location.search + location.hash );
563			__gaTracker('send', 'pageview' );
564			__gaTrackerLog( "Hash change to: " + location.pathname + location.search + location.hash );
565		} else {
566			__gaTrackerLog( "Hash change to (untracked): " + location.pathname + location.search + location.hash );
567		}
568	}
569
570	/* Attach the event to all clicks in the document after page has loaded */
571	var __gaTrackerWindow    = window;
572	if ( __gaTrackerWindow.addEventListener ) {
573		__gaTrackerWindow.addEventListener(
574			"load",
575			function() {
576				document.body.addEventListener(
577					"click",
578					__gaTrackerClickEvent,
579					 false
580				);
581			},
582			false
583		);
584		window.addEventListener("hashchange", __gaTrackerHashChangeEvent, false	);
585	} else {
586		if ( __gaTrackerWindow.attachEvent ) {
587			__gaTrackerWindow.attachEvent(
588				"onload",
589				function() {
590					document.body.attachEvent( "onclick", __gaTrackerClickEvent);
591				}
592			);
593			window.attachEvent( "onhashchange", __gaTrackerHashChangeEvent);
594		}
595	}
596
597	if (typeof String.prototype.endsWith !== 'function') {
598		String.prototype.endsWith = function(suffix) {
599			return this.indexOf(suffix, this.length - suffix.length) !== -1;
600		};
601	}
602	if (typeof String.prototype.startsWith !== 'function') {
603		String.prototype.startsWith = function(prefix) {
604			return this.indexOf(prefix) === 0;
605		};
606	}
607
608	if ( typeof Array.prototype.lastIndexOf !== 'function' ) {
609	  Array.prototype.lastIndexOf = function(searchElement /*, fromIndex*/) {
610		'use strict';
611
612		if (this === void 0 || this === null) {
613		  throw new TypeError();
614		}
615
616		var n, k,
617		  t = Object(this),
618		  len = t.length >>> 0; /* jshint ignore:line */
619		if (len === 0) {
620		  return -1;
621		}
622
623		n = len - 1;
624		if (arguments.length > 1) {
625		  n = Number(arguments[1]);
626		  if (n != n) {
627			n = 0;
628		  }
629		  else if (n != 0 && n != (1 / 0) && n != -(1 / 0)) { /* jshint ignore:line */
630			n = (n > 0 || -1) * Math.floor(Math.abs(n));
631		  }
632		}
633
634		for (k = n >= 0 ? Math.min(n, len - 1) : len - Math.abs(n); k >= 0; k--) {
635		  if (k in t && t[k] === searchElement) {
636			return k;
637		  }
638		}
639		return -1;
640	  };
641	}
642};
643var ExactMetricsObject = new ExactMetrics();

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.