plugin/boomerang/boomerang-1.0.0.js
/**
	 * Replace original window.XMLHttpRequest with our implementation instrumenting
	 * any AJAX Requests happening afterwards. This will also enable instrumentation
	 * of mouse events (clicks) and start the {@link MutationHandler}
	 */
Replace original window.XMLHttpRequest with our implementation instrumenting
any AJAX Requests happening afterwards. This will also enable instrumentation
of mouse events (clicks) and start the  MutationHandler
Replace original window . XMLHttpRequest with our implementation instrumenting any AJAX Requests happening afterwards . This will also enable instrumentation of mouse events ( clicks ) and start the MutationHandler
function instrumentXHR() {
		if (BOOMR.proxy_XMLHttpRequest &&
			BOOMR.proxy_XMLHttpRequest === w.XMLHttpRequest) {
			return;
		}
		if (BOOMR.proxy_XMLHttpRequest &&
			BOOMR.orig_XMLHttpRequest &&
			BOOMR.orig_XMLHttpRequest === w.XMLHttpRequest) {
			w.XMLHttpRequest = BOOMR.proxy_XMLHttpRequest;
			MutationHandler.start();
			return;
		}
		BOOMR.orig_XMLHttpRequest = w.orig_XMLHttpRequest || w.XMLHttpRequest;
		MutationHandler.start();
		instrumentClick();
		BOOMR.proxy_XMLHttpRequest = function() {
			var req, resource = { timing: {}, initiator: "xhr" }, orig_open, orig_send,
			    opened = false, excluded = false;
			req = new BOOMR.orig_XMLHttpRequest();
			orig_open = req.open;
			orig_send = req.send;
			req.open = function(method, url, async) {
				a.href = url;
				if (impl.excludeFilter(a)) {
					excluded = true;
					return orig_open.apply(req, arguments);
				}
				excluded = false;
				if (typeof async === "undefined") {
					async = true;
				}
				BOOMR.fireEvent("xhr_init", "xhr");
				function addListener(ename, stat) {
					req.addEventListener(
						ename,
						function() {
							if (ename === "readystatechange") {
								resource.timing[readyStateMap[req.readyState]] = BOOMR.now();
								if (req.readyState === 4 && req.status !== 0) {
									if (req.status < 200 || req.status >= 400) {
										resource.status = req.status;
									}
									if (impl.captureXhrRequestResponse) {
										resource.response = {
											text: (req.responseType === "" || req.responseType === "text") ? req.responseText : null,
											xml: (req.responseType === "" || req.responseType === "document") ? req.responseXML : null,
											raw: req.response,
											json: req.responseJSON
										};
										 Work around browser bugs where our Boomerang frame's Object is not equal
										 to the main frame's Object.  This affects "isPlainObj()"-like checks that
										 validate the .constructor is equal to the main frame's Object.
										 e.g.
										 https:github.com/facebook/immutable-js/blob/master/src/utils/isPlainObj.js
										 This seems to mostly affect Safari 11.1.
										if (req.response &&
										    req.response.constructor &&
										    req.response.constructor === BOOMR.boomerang_frame.Object &&
										    BOOMR.boomerang_frame.Object !== w.Object) {
											try {
												 try to switch the constructor to the main window
												req.response.constructor = w.Object;
											}
											catch (e) {
												 NOP
											}
										}
									}
									impl.loadFinished(resource);
								}
								else if (req.readyState === 0 && typeof resource.timing.open === "number") {
									 something called .abort() after the request was started
									resource.status = XHR_STATUS_ABORT;
									impl.loadFinished(resource);
								}
							}
							else {
								 load, timeout, error, abort
								if (ename === "load") {
									if (req.status !== 0 && (req.status < 200 || req.status >= 400)) {
										resource.status = req.status;
									}
								}
								else {
									 this is a timeout/error/abort, so add the status code
									resource.status = (typeof stat === "undefined" ? req.status : stat);
								}
								impl.loadFinished(resource);
							}
						},
						false
					);
				}
				 .open() can be called multiple times (before .send()) - just make
				 sure that we don't track this as a new request, or add additional
				 event listeners
				if (!opened) {
					if (async) {
						addListener("readystatechange");
					}
					addListener("load");
					addListener("timeout", XHR_STATUS_TIMEOUT);
					addListener("error",   XHR_STATUS_ERROR);
					addListener("abort",   XHR_STATUS_ABORT);
				}
				resource.url = a.href;
				resource.method = method;
				resource.type = "xhr";
				 reset any statuses from previous calls to .open()
				delete resource.status;
				if (!async) {
					resource.synchronous = true;
				}
				 note we've called .open
				opened = true;
				try {
					return orig_open.apply(req, arguments);
				}
				catch (e) {
					 if there was an exception during .open(), .send() won't work either,
					 so let's fire loadFinished now
					resource.status = XHR_STATUS_OPEN_EXCEPTION;
					impl.loadFinished(resource);
					 rethrow the native method's exception
					throw e;
				}
			};
			req.send = function(data) {
				if (excluded) {
					 this xhr is excluded from instrumentation, call the original send method
					return orig_send.apply(req, arguments);
				}
				if (impl.captureXhrRequestResponse) {
					req.resource.requestPayload = data;
				}
				BOOMR.fireEvent("xhr_send", req);
				handler.addEvent(resource);
				resource.timing.requestStart = BOOMR.now();
				 call the original send method unless there was an error
				 during .open
				if (typeof resource.status === "undefined" ||
				    resource.status !== XHR_STATUS_OPEN_EXCEPTION) {
					return orig_send.apply(req, arguments);
				}
			};
			req.resource = resource;
			return req;
		};
		BOOMR.proxy_XMLHttpRequest.UNSENT = 0;
		BOOMR.proxy_XMLHttpRequest.OPENED = 1;
		BOOMR.proxy_XMLHttpRequest.HEADERS_RECEIVED = 2;
		BOOMR.proxy_XMLHttpRequest.LOADING = 3;
		BOOMR.proxy_XMLHttpRequest.DONE = 4;
		 set our proxy's prototype to the original XHR prototype, in case anyone
		 is using it to save state
		BOOMR.proxy_XMLHttpRequest.prototype = BOOMR.orig_XMLHttpRequest.prototype;
		 Overwrite window.XMLHttpRequest, ensuring the original is swapped back in
		 if the Boomerang IFRAME is unloaded.  uninstrumentXHR() may also
		 be used to swap the original back in.
		BOOMR.utils.overwriteNative(w, "XMLHttpRequest", BOOMR.proxy_XMLHttpRequest);
	}
function instrumentXHR ( ) { if ( BOOMR . proxy_XMLHttpRequest && BOOMR . proxy_XMLHttpRequest === w . XMLHttpRequest ) { return ; } if ( BOOMR . proxy_XMLHttpRequest && BOOMR . orig_XMLHttpRequest && BOOMR . orig_XMLHttpRequest === w . XMLHttpRequest ) { w . XMLHttpRequest = BOOMR . proxy_XMLHttpRequest ; MutationHandler . start ( ) ; return ; } BOOMR . orig_XMLHttpRequest = w . orig_XMLHttpRequest || w . XMLHttpRequest ; MutationHandler . start ( ) ; instrumentClick ( ) ; BOOMR . proxy_XMLHttpRequest = function ( ) { var req , resource = { timing : { } , initiator : "xhr" } , orig_open , orig_send , opened = false , excluded = false ; req = new BOOMR . orig_XMLHttpRequest ( ) ; orig_open = req . open ; orig_send = req . send ; req . open = function ( method , url , async ) { a . href = url ; if ( impl . excludeFilter ( a ) ) { excluded = true ; return orig_open . apply ( req , arguments ) ; } excluded = false ; if ( typeof async === "undefined" ) { async = true ; } BOOMR . fireEvent ( "xhr_init" , "xhr" ) ; function addListener ( ename , stat ) { req . addEventListener ( ename , function ( ) { if ( ename === "readystatechange" ) { resource . timing [ readyStateMap [ req . readyState ] ] = BOOMR . now ( ) ; if ( req . readyState === 4 && req . status !== 0 ) { if ( req . status < 200 || req . status >= 400 ) { resource . status = req . status ; } if ( impl . captureXhrRequestResponse ) { resource . response = { text : ( req . responseType === "" || req . responseType === "text" ) ? req . responseText : null , xml : ( req . responseType === "" || req . responseType === "document" ) ? req . responseXML : null , raw : req . response , json : req . responseJSON } ; if ( req . response && req . response . constructor && req . response . constructor === BOOMR . boomerang_frame . Object && BOOMR . boomerang_frame . Object !== w . Object ) { try { req . response . constructor = w . Object ; } catch ( e ) { } } } impl . loadFinished ( resource ) ; } else if ( req . readyState === 0 && typeof resource . timing . open === "number" ) { resource . status = XHR_STATUS_ABORT ; impl . loadFinished ( resource ) ; } } else { if ( ename === "load" ) { if ( req . status !== 0 && ( req . status < 200 || req . status >= 400 ) ) { resource . status = req . status ; } } else { resource . status = ( typeof stat === "undefined" ? req . status : stat ) ; } impl . loadFinished ( resource ) ; } } , false ) ; } if ( ! opened ) { if ( async ) { addListener ( "readystatechange" ) ; } addListener ( "load" ) ; addListener ( "timeout" , XHR_STATUS_TIMEOUT ) ; addListener ( "error" , XHR_STATUS_ERROR ) ; addListener ( "abort" , XHR_STATUS_ABORT ) ; } resource . url = a . href ; resource . method = method ; resource . type = "xhr" ; delete resource . status ; if ( ! async ) { resource . synchronous = true ; } opened = true ; try { return orig_open . apply ( req , arguments ) ; } catch ( e ) { resource . status = XHR_STATUS_OPEN_EXCEPTION ; impl . loadFinished ( resource ) ; throw e ; } } ; req . send = function ( data ) { if ( excluded ) { return orig_send . apply ( req , arguments ) ; } if ( impl . captureXhrRequestResponse ) { req . resource . requestPayload = data ; } BOOMR . fireEvent ( "xhr_send" , req ) ; handler . addEvent ( resource ) ; resource . timing . requestStart = BOOMR . now ( ) ; if ( typeof resource . status === "undefined" || resource . status !== XHR_STATUS_OPEN_EXCEPTION ) { return orig_send . apply ( req , arguments ) ; } } ; req . resource = resource ; return req ; } ; BOOMR . proxy_XMLHttpRequest . UNSENT = 0 ; BOOMR . proxy_XMLHttpRequest . OPENED = 1 ; BOOMR . proxy_XMLHttpRequest . HEADERS_RECEIVED = 2 ; BOOMR . proxy_XMLHttpRequest . LOADING = 3 ; BOOMR . proxy_XMLHttpRequest . DONE = 4 ; BOOMR . proxy_XMLHttpRequest . prototype = BOOMR . orig_XMLHttpRequest . prototype ; BOOMR . utils . overwriteNative ( w , "XMLHttpRequest" , BOOMR . proxy_XMLHttpRequest ) ; }
Replace original window.XMLHttpRequest with our implementation instrumenting
 any AJAX Requests happening afterwards.
Replace original window . XMLHttpRequest with our implementation instrumenting any AJAX Requests happening afterwards .
// already instrumented // was once instrumented and then uninstrumented, so just reapply the old instrumented object // if there's a orig_XMLHttpRequest on the window, use that first (if another lib is overwriting XHR) /**
		 * Proxy `XMLHttpRequest` object
		 * @class ProxyXHRImplementation
		 */ /**
		 * Open an XMLHttpRequest.
		 * If the URL passed as a second argument is in the BOOMR.xhr_exclude list ignore it and move on to request it
		 * Otherwise add it to our list of resources to monitor and later beacon on.
		 *
		 * If an exception is caught will call loadFinished and set resource.status to {@link XHR_STATUS_OPEN_EXCEPTION}
		 * Should the resource fail to load for any of the following reasons resource.stat status code will be set to:
		 *
		 * - timeout {Event} {@link XHR_STATUS_TIMEOUT}
		 * - error {Event} {@link XHR_STATUS_ERROR}
		 * - abort {Event} {@link XHR_STATUS_ABORT}
		 *
		 * @param {string} method HTTP request method
		 * @param {string} url URL to request on
		 * @param {boolean} [async] If `true` will setup the EventListeners for XHR events otherwise will set the resource
		 * to synchronous. If `true` or `undefined` will be automatically set to asynchronous
		 *
		 * @memberof ProxyXHRImplementation
		 */ // this xhr should be excluded from instrumentation // call the original open method // Default value of async is true /**
				 * Setup an {EventListener} for Event @param{ename}. This function will
				 * make sure the timestamp for the resources request is set and calls
				 * loadFinished should the resource have finished.
				 *
				 * See {@link open()} for it's usage
				 *
				 * @param ename {String} Eventname to listen on via addEventListener
				 * @param stat {String} if that {@link ename} is reached set this
				 * as the status of the resource
				 *
				 * @memberof ProxyXHRImplementation
				 */ // Listen here as well, as DOM changes might happen on other listeners // of readyState = 4 (complete), and we want to make sure we've // started the addEvent() if so.  Only listen if the status is non-zero, // meaning the request wasn't aborted.  Aborted requests will fire the // next handler. // put the HTTP error code on the resource if it's not a success // // Work around browser bugs where our Boomerang frame's Object is not equal // to the main frame's Object.  This affects "isPlainObj()"-like checks that // validate the .constructor is equal to the main frame's Object. // e.g. // https://github.com/facebook/immutable-js/blob/master/src/utils/isPlainObj.js // This seems to mostly affect Safari 11.1. // // try to switch the constructor to the main window // NOP // something called .abort() after the request was started // load, timeout, error, abort // put the HTTP error code on the resource if it's not a success // this is a timeout/error/abort, so add the status code // .open() can be called multiple times (before .send()) - just make // sure that we don't track this as a new request, or add additional // event listeners // reset any statuses from previous calls to .open() // note we've called .open // call the original open method // if there was an exception during .open(), .send() won't work either, // so let's fire loadFinished now // rethrow the native method's exception /**
			 * Mark requestStart timestamp and start the request unless the resource
			 * has already been marked as having an error code or a result to itself.
			 *
			 * @returns {Object} The data normal XHR.send() would return
			 *
			 * @memberof ProxyXHRImplementation
			 */ // this xhr is excluded from instrumentation, call the original send method // call the original send method unless there was an error // during .open // set our proxy's prototype to the original XHR prototype, in case anyone // is using it to save state // Overwrite window.XMLHttpRequest, ensuring the original is swapped back in // if the Boomerang IFRAME is unloaded.  uninstrumentXHR() may also // be used to swap the original back in.