You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@flagon.apache.org by po...@apache.org on 2019/09/27 06:15:57 UTC

[incubator-flagon-useralejs] 01/01: fixing merge conflicts

This is an automated email from the ASF dual-hosted git repository.

poorejc pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-flagon-useralejs.git

commit fe1b477fd1da22ae36e45d22f9b8f3236408bfeb
Merge: f82c6d5 a382e91
Author: poorejc <po...@apache.org>
AuthorDate: Fri Sep 27 02:15:14 2019 -0400

    fixing merge conflicts

 build/UserAleWebExtension/background.js |  769 +++++++--------
 build/UserAleWebExtension/content.js    | 1567 ++++++++++++++++---------------
 build/UserAleWebExtension/options.js    |   38 +-
 build/userale-2.0.2.js                  |  266 +++---
 build/userale-2.0.2.min.js              |    2 +-
 example/index.html                      |   16 +-
 package-lock.json                       |   48 +-
 package.json                            |    1 +
 src/attachHandlers.js                   |   20 +-
 src/getInitialSettings.js               |   28 +-
 src/sendLogs.js                         |   18 +
 test/getInitialSettings_spec.js         |    1 +
 test/testUtils.js                       |   23 +-
 13 files changed, 1507 insertions(+), 1290 deletions(-)

diff --cc build/UserAleWebExtension/content.js
index ad46097,ae2be33..345486f
--- a/build/UserAleWebExtension/content.js
+++ b/build/UserAleWebExtension/content.js
@@@ -50,760 -50,812 +50,839 @@@ var ADD_LOG = prefix + 'ADD_LOG'
  
  var version = "2.0.2";
  
- /*
-  * Licensed to the Apache Software Foundation (ASF) under one or more
-  * contributor license agreements.  See the NOTICE file distributed with
-  * this work for additional information regarding copyright ownership.
-  * The ASF licenses this file to You under the Apache License, Version 2.0
-  * (the "License"); you may not use this file except in compliance with
-  * the License.  You may obtain a copy of the License at
-  * 
-  *   http://www.apache.org/licenses/LICENSE-2.0
-  * 
-  * Unless required by applicable law or agreed to in writing, software
-  * distributed under the License is distributed on an "AS IS" BASIS,
-  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  * See the License for the specific language governing permissions and
-  * limitations under the License.
-  */
- 
- /**
-  * Extracts the initial configuration settings from the
-  * currently executing script tag.
-  * @return {Object} The extracted configuration object
-  */
- function getInitialSettings() {
-   var settings = {};
- 
-   var script = document.currentScript || (function () {
-     var scripts = document.getElementsByTagName('script');
-     return scripts[scripts.length - 1];
-   })();
- 
-   var get = script ? script.getAttribute.bind(script) : function() { return null; };
- 
-   settings.autostart = get('data-autostart') === 'false' ? false : true;
-   settings.url = get('data-url') || 'http://localhost:8000';
-   settings.transmitInterval = +get('data-interval') || 5000;
-   settings.logCountThreshold = +get('data-threshold') || 5;
-   settings.userId = get('data-user') || null;
-   settings.version = get('data-version') || null;
-   settings.logDetails = get('data-log-details') === 'true' ? true : false;
-   settings.resolution = +get('data-resolution') || 500;
-   settings.toolName = get('data-tool') || null;
-   settings.userFromParams = get('data-user-from-params') || null;
-   settings.time = timeStampScale(document.createEvent('CustomEvent'));
-   settings.sessionID = get('data-session') || 'session_' + String(Date.now());
- 
-   return settings;
- }
- 
- /**
-  * Creates a function to normalize the timestamp of the provided event.
-  * @param  {Object} e An event containing a timeStamp property.
-  * @return {timeStampScale~tsScaler}   The timestamp normalizing function.
-  */
- function timeStampScale(e) {
-   if (e.timeStamp && e.timeStamp > 0) {
-     var delta = Date.now() - e.timeStamp;
-     /**
-      * Returns a timestamp depending on various browser quirks.
-      * @param  {?Number} ts A timestamp to use for normalization.
-      * @return {Number} A normalized timestamp.
-      */
-     var tsScaler;
- 
-     if (delta < 0) {
-       tsScaler = function () {
-         return e.timeStamp / 1000;
-       };
-     } else if (delta > e.timeStamp) {
-       var navStart = performance.timing.navigationStart;
-       tsScaler = function (ts) {
-         return ts + navStart;
-       };
-     } else {
-       tsScaler = function (ts) {
-         return ts;
-       };
-     }
-   } else {
-     tsScaler = function () { return Date.now(); };
-   }
- 
-   return tsScaler;
- }
- 
- /*
-  * Licensed to the Apache Software Foundation (ASF) under one or more
-  * contributor license agreements.  See the NOTICE file distributed with
-  * this work for additional information regarding copyright ownership.
-  * The ASF licenses this file to You under the Apache License, Version 2.0
-  * (the "License"); you may not use this file except in compliance with
-  * the License.  You may obtain a copy of the License at
-  * 
-  *   http://www.apache.org/licenses/LICENSE-2.0
-  * 
-  * Unless required by applicable law or agreed to in writing, software
-  * distributed under the License is distributed on an "AS IS" BASIS,
-  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  * See the License for the specific language governing permissions and
-  * limitations under the License.
-  */
- 
- /**
-  * Shallow merges the first argument with the second.
-  * Retrieves/updates the userid if userFromParams is provided.
-  * @param  {Object} config    Current configuration object to be merged into.
-  * @param  {Object} newConfig Configuration object to merge into the current config.
-  */
- function configure(config, newConfig) {
-   Object.keys(newConfig).forEach(function(option) {
-     if (option === 'userFromParams') {
-       var userId = getUserIdFromParams(newConfig[option]);
-       if (userId) {
-         config.userId = userId;
-       }
-     }
-     config[option] = newConfig[option];
-   });
- }
- 
- /**
-  * Attempts to extract the userid from the query parameters of the URL.
-  * @param  {string} param The name of the query parameter containing the userid.
-  * @return {string|null}       The extracted/decoded userid, or null if none is found.
-  */
- function getUserIdFromParams(param) {
-   var userField = param;
-   var regex = new RegExp('[?&]' + userField + '(=([^&#]*)|&|#|$)');
-   var results = window.location.href.match(regex);
- 
-   if (results && results[2]) {
-     return decodeURIComponent(results[2].replace(/\+/g, ' '));
-   } else {
-     return null;
-   }
- }
- 
- /*
-  * Licensed to the Apache Software Foundation (ASF) under one or more
-  * contributor license agreements.  See the NOTICE file distributed with
-  * this work for additional information regarding copyright ownership.
-  * The ASF licenses this file to You under the Apache License, Version 2.0
-  * (the "License"); you may not use this file except in compliance with
-  * the License.  You may obtain a copy of the License at
-  * 
-  *   http://www.apache.org/licenses/LICENSE-2.0
-  * 
-  * Unless required by applicable law or agreed to in writing, software
-  * distributed under the License is distributed on an "AS IS" BASIS,
-  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  * See the License for the specific language governing permissions and
-  * limitations under the License.
-  */
- 
- var logs;
- var config;
- 
- // Interval Logging Globals
- var intervalID;
- var intervalType;
- var intervalPath;
- var intervalTimer;
- var intervalCounter;
- var intervalLog;
- 
- var filterHandler = null;
- var mapHandler = null;
- 
- /**
-  * Assigns a handler to filter logs out of the queue.
-  * @param  {Function} callback The handler to invoke when logging.
-  */
- function setLogFilter(callback) {
-   filterHandler = callback;
- }
- 
- 
- /**
-  * Assigns the config and log container to be used by the logging functions.
-  * @param  {Array} newLogs   Log container.
-  * @param  {Object} newConfig Configuration to use while logging.
-  */
- function initPackager(newLogs, newConfig) {
-   logs = newLogs;
-   config = newConfig;
-   filterHandler = null;
-   mapHandler = null;
-   intervalID = null;
-   intervalType = null;
-   intervalPath = null;
-   intervalTimer = null;
-   intervalCounter = 0;
-   intervalLog = null;
- }
- 
- /**
-  * Transforms the provided event into a log and appends it to the log container.
-  * @param  {Object} e         The event to be logged.
-  * @param  {Function} detailFcn The function to extract additional log parameters from the event.
-  * @return {boolean}           Whether the event was logged.
-  */
- function packageLog(e, detailFcn) {
-   if (!config.on) {
-     return false;
-   }
- 
-   var details = null;
-   if (detailFcn) {
-     details = detailFcn(e);
-   }
- 
-   var timeFields = extractTimeFields(
-     (e.timeStamp && e.timeStamp > 0) ? config.time(e.timeStamp) : Date.now()
-   );
- 
-   var log = {
-     'target' : getSelector(e.target),
-     'path' : buildPath(e),
-     'pageUrl': window.location.href,
-     'pageTitle': document.title,
-     'pageReferrer': document.referrer,
-     'clientTime' : timeFields.milli,
-     'microTime' : timeFields.micro,
-     'location' : getLocation(e),
-     'type' : e.type,
-     'logType': 'raw',
-     'userAction' : true,
-     'details' : details,
-     'userId' : config.userId,
-     'toolVersion' : config.version,
-     'toolName' : config.toolName,
-     'useraleVersion': config.useraleVersion,
-     'sessionID': config.sessionID
-   };
- 
-   if ((typeof filterHandler === 'function') && !filterHandler(log)) {
-     return false;
-   }
- 
-   if (typeof mapHandler === 'function') {
-     log = mapHandler(log);
-   }
- 
-   logs.push(log);
- 
-   return true;
- }
- 
- /**
-  * Extract the millisecond and microsecond portions of a timestamp.
-  * @param  {Number} timeStamp The timestamp to split into millisecond and microsecond fields.
-  * @return {Object}           An object containing the millisecond
-  *                            and microsecond portions of the timestamp.
-  */
- function extractTimeFields(timeStamp) {
-   return {
-     milli: Math.floor(timeStamp),
-     micro: Number((timeStamp % 1).toFixed(3)),
-   };
- }
- 
- /**
-  * Track intervals and gather details about it.
-  * @param {Object} e
-  * @return boolean
-  */
- function packageIntervalLog(e) {
-     var target = getSelector(e.target);
-     var path = buildPath(e);
-     var type = e.type;
-     var timestamp = Math.floor((e.timeStamp && e.timeStamp > 0) ? config.time(e.timeStamp) : Date.now());
- 
-     // Init - this should only happen once on initialization
-     if (intervalID == null) {
-         intervalID = target;
-         intervalType = type;
-         intervalPath = path;
-         intervalTimer = timestamp;
-         intervalCounter = 0;
-     }
- 
-     if (intervalID !== target || intervalType !== type) {
-         // When to create log? On transition end
-         // @todo Possible for intervalLog to not be pushed in the event the interval never ends...
- 
-         intervalLog = {
-             'target': intervalID,
-             'path': intervalPath,
-             'pageUrl': window.location.href,
-             'pageTitle': document.title,
-             'pageReferrer': document.referrer,
-             'count': intervalCounter,
-             'duration': timestamp - intervalTimer,  // microseconds
-             'startTime': intervalTimer,
-             'endTime': timestamp,
-             'type': intervalType,
-             'logType': 'interval',    
-             'targetChange': intervalID !== target,
-             'typeChange': intervalType !== type,
-             'userAction': false,
-             'userId': config.userId,
-             'toolVersion': config.version,
-             'toolName': config.toolName,
-             'useraleVersion': config.useraleVersion,
-             'sessionID': config.sessionID
-         };
- 
-         if (typeof filterHandler === 'function' && !filterHandler(intervalLog)) {
-           return false;
-         }
- 
-         if (typeof mapHandler === 'function') {
-           intervalLog = mapHandler(intervalLog);
-         }
- 
-         logs.push(intervalLog);
- 
-         // Reset
-         intervalID = target;
-         intervalType = type;
-         intervalPath = path;
-         intervalTimer = timestamp;
-         intervalCounter = 0;
-     }
- 
-     // Interval is still occuring, just update counter
-     if (intervalID == target && intervalType == type) {
-         intervalCounter = intervalCounter + 1;
-     }
- 
-     return true;
- }
- 
- /**
-  * Extracts coordinate information from the event
-  * depending on a few browser quirks.
-  * @param  {Object} e The event to extract coordinate information from.
-  * @return {Object}   An object containing nullable x and y coordinates for the event.
-  */
- function getLocation(e) {
-   if (e.pageX != null) {
-     return { 'x' : e.pageX, 'y' : e.pageY };
-   } else if (e.clientX != null) {
-     return { 'x' : document.documentElement.scrollLeft + e.clientX, 'y' : document.documentElement.scrollTop + e.clientY };
-   } else {
-     return { 'x' : null, 'y' : null };
-   }
- }
- 
- /**
-  * Builds a string CSS selector from the provided element
-  * @param  {HTMLElement} ele The element from which the selector is built.
-  * @return {string}     The CSS selector for the element, or Unknown if it can't be determined.
-  */
- function getSelector(ele) {
-   if (ele.localName) {
-     return ele.localName + (ele.id ? ('#' + ele.id) : '') + (ele.className ? ('.' + ele.className) : '');
-   } else if (ele.nodeName) {
-     return ele.nodeName + (ele.id ? ('#' + ele.id) : '') + (ele.className ? ('.' + ele.className) : '');
-   } else if (ele && ele.document && ele.location && ele.alert && ele.setInterval) {
-     return "Window";
-   } else {
-     return "Unknown";
-   }
- }
- 
- /**
-  * Builds an array of elements from the provided event target, to the root element.
-  * @param  {Object} e Event from which the path should be built.
-  * @return {HTMLElement[]}   Array of elements, starting at the event target, ending at the root element.
-  */
- function buildPath(e) {
-   var path = [];
-   if (e.path) {
-     path = e.path;
-   } else {
-     var ele = e.target;
-     while(ele) {
-       path.push(ele);
-       ele = ele.parentElement;
-     }
-   }
- 
-   return selectorizePath(path);
- }
- 
- /**
-  * Builds a CSS selector path from the provided list of elements.
-  * @param  {HTMLElement[]} path Array of HTMLElements from which the path should be built.
-  * @return {string[]}      Array of string CSS selectors.
-  */
- function selectorizePath(path) {
-   var i = 0;
-   var pathEle;
-   var pathSelectors = [];
-   while (pathEle = path[i]) {
-     pathSelectors.push(getSelector(pathEle));
-     ++i;
-   }
-   return pathSelectors;
- }
- 
- /*
-  * Licensed to the Apache Software Foundation (ASF) under one or more
-  * contributor license agreements.  See the NOTICE file distributed with
-  * this work for additional information regarding copyright ownership.
-  * The ASF licenses this file to You under the Apache License, Version 2.0
-  * (the "License"); you may not use this file except in compliance with
-  * the License.  You may obtain a copy of the License at
-  * 
-  *   http://www.apache.org/licenses/LICENSE-2.0
-  * 
-  * Unless required by applicable law or agreed to in writing, software
-  * distributed under the License is distributed on an "AS IS" BASIS,
-  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  * See the License for the specific language governing permissions and
-  * limitations under the License.
-  */
- 
- var events;
- var bufferBools;
- var bufferedEvents;
- //@todo: Investigate drag events and their behavior
- var intervalEvents = ['click', 'focus', 'blur', 'input', 'change', 'mouseover', 'submit'];
- var windowEvents = ['load', 'blur', 'focus'];
- 
- /**
-  * Maps an event to an object containing useful information.
-  * @param  {Object} e Event to extract data from
-  */
- function extractMouseEvent(e) {
-   return {
-     'clicks' : e.detail,
-     'ctrl' : e.ctrlKey,
-     'alt' : e.altKey,
-     'shift' : e.shiftKey,
-     'meta' : e.metaKey
-   };
- }
- 
- /**
-  * Defines the way information is extracted from various events.
-  * Also defines which events we will listen to.
-  * @param  {Object} config Configuration object to read from.
-  */
- function defineDetails(config) {
-   // Events list
-   // Keys are event types
-   // Values are functions that return details object if applicable
-   events = {
-     'click' : extractMouseEvent,
-     'dblclick' : extractMouseEvent,
-     'mousedown' : extractMouseEvent,
-     'mouseup' : extractMouseEvent,
-     'focus' : null,
-     'blur' : null,
-     'input' : config.logDetails ? function(e) { return { 'value' : e.target.value }; } : null,
-     'change' : config.logDetails ? function(e) { return { 'value' : e.target.value }; } : null,
-     'dragstart' : null,
-     'dragend' : null,
-     'drag' : null,
-     'drop' : null,
-     'keydown' : config.logDetails ? function(e) { return { 'key' : e.keyCode, 'ctrl' : e.ctrlKey, 'alt' : e.altKey, 'shift' : e.shiftKey, 'meta' : e.metaKey }; } : null,
-     'mouseover' : null,
-     'submit' : null
-   };
- 
-   bufferBools = {};
-   bufferedEvents = {
-     'wheel' : function(e) { return { 'x' : e.deltaX, 'y' : e.deltaY, 'z' : e.deltaZ }; },
-     'scroll' : function() { return { 'x' : window.scrollX, 'y' : window.scrollY }; },
-     'resize' : function() { return { 'width' : window.outerWidth, 'height' : window.outerHeight }; }
-   };
- }
- 
- /**
-  * Hooks the event handlers for each event type of interest.
-  * @param  {Object} config Configuration object to use.
-  * @return {boolean}        Whether the operation succeeded
-  */
- function attachHandlers(config) {
-   defineDetails(config);
- 
-   Object.keys(events).forEach(function(ev) {
-     document.addEventListener(ev, function(e) {
-       packageLog(e, events[ev]);
-     }, true);
-   });
- 
-   intervalEvents.forEach(function(ev) {
-     document.addEventListener(ev, function(e) {
-         packageIntervalLog(e);
-     }, true);
-   });
- 
-   Object.keys(bufferedEvents).forEach(function(ev) {
-     bufferBools[ev] = true;
- 
-     window.addEventListener(ev, function(e) {
-       if (bufferBools[ev]) {
-         bufferBools[ev] = false;
-         packageLog(e, bufferedEvents[ev]);
-         setTimeout(function() { bufferBools[ev] = true; }, config.resolution);
-       }
-     }, true);
-   });
- 
-   windowEvents.forEach(function(ev) {
-     window.addEventListener(ev, function(e) {
-       packageLog(e, function() { return { 'window' : true }; });
-     }, true);
-   });
- 
-   return true;
- }
- 
- /*
-  * Licensed to the Apache Software Foundation (ASF) under one or more
-  * contributor license agreements.  See the NOTICE file distributed with
-  * this work for additional information regarding copyright ownership.
-  * The ASF licenses this file to You under the Apache License, Version 2.0
-  * (the "License"); you may not use this file except in compliance with
-  * the License.  You may obtain a copy of the License at
-  * 
-  *   http://www.apache.org/licenses/LICENSE-2.0
-  * 
-  * Unless required by applicable law or agreed to in writing, software
-  * distributed under the License is distributed on an "AS IS" BASIS,
-  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  * See the License for the specific language governing permissions and
-  * limitations under the License.
-  */
- 
- var sendIntervalId = null;
- 
- /**
-  * Initializes the log queue processors.
-  * @param  {Array} logs   Array of logs to append to.
-  * @param  {Object} config Configuration object to use when logging.
-  */
- function initSender(logs, config) {
-   if (sendIntervalId !== null) {
-     clearInterval(sendIntervalId);
-   }
- 
-   sendIntervalId = sendOnInterval(logs, config);
-   sendOnClose(logs, config);
- }
- 
- /**
-  * Checks the provided log array on an interval, flushing the logs
-  * if the queue has reached the threshold specified by the provided config.
-  * @param  {Array} logs   Array of logs to read from.
-  * @param  {Object} config Configuration object to be read from.
-  * @return {Number}        The newly created interval id.
-  */
- function sendOnInterval(logs, config) {
-   return setInterval(function() {
-     if (!config.on) {
-       return;
-     }
- 
-     if (logs.length >= config.logCountThreshold) {
-       sendLogs(logs.slice(0), config.url, 0); // Send a copy
-       logs.splice(0); // Clear array reference (no reassignment)
-     }
-   }, config.transmitInterval);
- }
- 
- /**
-  * Attempts to flush the remaining logs when the window is closed.
-  * @param  {Array} logs   Array of logs to be flushed.
-  * @param  {Object} config Configuration object to be read from.
-  */
- function sendOnClose(logs, config) {
-   if (!config.on) {
-     return;
-   }
- 
-   if (navigator.sendBeacon) {
-     window.addEventListener('unload', function() {
-       navigator.sendBeacon(config.url, JSON.stringify(logs));
-     });
-   } else {
-     window.addEventListener('beforeunload', function() {
-       if (logs.length > 0) {
-         sendLogs(logs, config.url, 1);
-       }
-     });
-   }
- }
- 
- /**
-  * Sends the provided array of logs to the specified url,
-  * retrying the request up to the specified number of retries.
-  * @param  {Array} logs    Array of logs to send.
-  * @param  {string} url     URL to send the POST request to.
-  * @param  {Number} retries Maximum number of attempts to send the logs.
-  */
- function sendLogs(logs, url, retries) {
-   var req = new XMLHttpRequest();
- 
-   var data = JSON.stringify(logs);
- 
-   req.open('POST', url);
-   req.setRequestHeader('Content-type', 'application/json;charset=UTF-8');
- 
-   req.onreadystatechange = function() {
-     if (req.readyState === 4 && req.status !== 200) {
-       if (retries > 0) {
-         sendLogs(logs, url, retries--);
-       }
-     }
-   };
- 
-   req.send(data);
- }
- 
- /*
-  * Licensed to the Apache Software Foundation (ASF) under one or more
-  * contributor license agreements.  See the NOTICE file distributed with
-  * this work for additional information regarding copyright ownership.
-  * The ASF licenses this file to You under the Apache License, Version 2.0
-  * (the "License"); you may not use this file except in compliance with
-  * the License.  You may obtain a copy of the License at
-  * 
-  *   http://www.apache.org/licenses/LICENSE-2.0
-  * 
-  * Unless required by applicable law or agreed to in writing, software
-  * distributed under the License is distributed on an "AS IS" BASIS,
-  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  * See the License for the specific language governing permissions and
-  * limitations under the License.
-  */
- 
- var config$1 = {};
- var logs$1 = [];
- var started = false;
- 
- // Start up Userale
- config$1.on = false;
- config$1.useraleVersion = version;
- 
- configure(config$1, getInitialSettings());
- initPackager(logs$1, config$1);
- 
- if (config$1.autostart) {
-   setup(config$1);
- }
- 
- /**
-  * Hooks the global event listener, and starts up the
-  * logging interval.
-  * @param  {Object} config Configuration settings for the logger
-  */
- function setup(config) {
-   if (!started) {
-     setTimeout(function() {
-       var state = document.readyState;
- 
-       if (state === 'interactive' || state === 'complete') {
-         attachHandlers(config);
-         initSender(logs$1, config);
-         started = config.on = true;
-       } else {
-         setup(config);
-       }
-     }, 100);
-   }
+ /*
+  * Licensed to the Apache Software Foundation (ASF) under one or more
+  * contributor license agreements.  See the NOTICE file distributed with
+  * this work for additional information regarding copyright ownership.
+  * The ASF licenses this file to You under the Apache License, Version 2.0
+  * (the 'License'); you may not use this file except in compliance with
+  * the License.  You may obtain a copy of the License at
+  * 
+  *   http://www.apache.org/licenses/LICENSE-2.0
+  * 
+  * Unless required by applicable law or agreed to in writing, software
+  * distributed under the License is distributed on an 'AS IS' BASIS,
+  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  * See the License for the specific language governing permissions and
+  * limitations under the License.
+  */
+ 
+  var sessionId = null;
+ 
+ /**
+  * Extracts the initial configuration settings from the
+  * currently executing script tag.
+  * @return {Object} The extracted configuration object
+  */
+ function getInitialSettings() {
+   var settings = {};
+ 
+   if (sessionId === null) {
+     sessionId = getSessionId('userAleSessionId', 'session_' + String(Date.now()));
+   }
+ 
+   var script = document.currentScript || (function () {
+     var scripts = document.getElementsByTagName('script');
+     return scripts[scripts.length - 1];
+   })();
+ 
+   var get = script ? script.getAttribute.bind(script) : function() { return null; };
+ 
+   settings.autostart = get('data-autostart') === 'false' ? false : true;
+   settings.url = get('data-url') || 'http://localhost:8000';
+   settings.transmitInterval = +get('data-interval') || 5000;
+   settings.logCountThreshold = +get('data-threshold') || 5;
+   settings.userId = get('data-user') || null;
+   settings.version = get('data-version') || null;
+   settings.logDetails = get('data-log-details') === 'true' ? true : false;
+   settings.resolution = +get('data-resolution') || 500;
+   settings.toolName = get('data-tool') || null;
+   settings.userFromParams = get('data-user-from-params') || null;
+   settings.time = timeStampScale(document.createEvent('CustomEvent'));
+   settings.sessionID = get('data-session') || sessionId;
+ 
+   return settings;
+ }
+ 
+ /**
+  * defines sessionId, stores it in sessionStorage, checks to see if there is a sessionId in
+  * storage when script is started. This prevents events like 'submit', which refresh page data
+  * from refreshing the current user session
+  *
+  */
+ function getSessionId(sessionKey, value){
+   if (window.sessionStorage.getItem(sessionKey) === null) {
+     window.sessionStorage.setItem(sessionKey, JSON.stringify(value));
+     return JSON.stringify(value);
+   }
+ 
+   return JSON.parse(window.sessionStorage.getItem(sessionKey));
+ }
+ 
+ 
+ /**
+  * Creates a function to normalize the timestamp of the provided event.
+  * @param  {Object} e An event containing a timeStamp property.
+  * @return {timeStampScale~tsScaler}   The timestamp normalizing function.
+  */
+ function timeStampScale(e) {
+   if (e.timeStamp && e.timeStamp > 0) {
+     var delta = Date.now() - e.timeStamp;
+     /**
+      * Returns a timestamp depending on various browser quirks.
+      * @param  {?Number} ts A timestamp to use for normalization.
+      * @return {Number} A normalized timestamp.
+      */
+     var tsScaler;
+ 
+     if (delta < 0) {
+       tsScaler = function () {
+         return e.timeStamp / 1000;
+       };
+     } else if (delta > e.timeStamp) {
+       var navStart = performance.timing.navigationStart;
+       tsScaler = function (ts) {
+         return ts + navStart;
+       };
+     } else {
+       tsScaler = function (ts) {
+         return ts;
+       };
+     }
+   } else {
+     tsScaler = function () { return Date.now(); };
+   }
+ 
+   return tsScaler;
  }
  
++<<<<<<< HEAD
 +/**
 + * Updates the current configuration
 + * object with the provided values.
 + * @param  {Object} newConfig The configuration options to use.
 + * @return {Object}           Returns the updated configuration.
 + */
 +function options(newConfig) {
 +  if (newConfig !== undefined) {
 +    configure(config$1, newConfig);
 +  }
 +
 +  return config$1;
++=======
+ /*
+  * Licensed to the Apache Software Foundation (ASF) under one or more
+  * contributor license agreements.  See the NOTICE file distributed with
+  * this work for additional information regarding copyright ownership.
+  * The ASF licenses this file to You under the Apache License, Version 2.0
+  * (the "License"); you may not use this file except in compliance with
+  * the License.  You may obtain a copy of the License at
+  * 
+  *   http://www.apache.org/licenses/LICENSE-2.0
+  * 
+  * Unless required by applicable law or agreed to in writing, software
+  * distributed under the License is distributed on an "AS IS" BASIS,
+  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  * See the License for the specific language governing permissions and
+  * limitations under the License.
+  */
+ 
+ /**
+  * Shallow merges the first argument with the second.
+  * Retrieves/updates the userid if userFromParams is provided.
+  * @param  {Object} config    Current configuration object to be merged into.
+  * @param  {Object} newConfig Configuration object to merge into the current config.
+  */
+ function configure(config, newConfig) {
+   Object.keys(newConfig).forEach(function(option) {
+     if (option === 'userFromParams') {
+       var userId = getUserIdFromParams(newConfig[option]);
+       if (userId) {
+         config.userId = userId;
+       }
+     }
+     config[option] = newConfig[option];
+   });
+ }
+ 
+ /**
+  * Attempts to extract the userid from the query parameters of the URL.
+  * @param  {string} param The name of the query parameter containing the userid.
+  * @return {string|null}       The extracted/decoded userid, or null if none is found.
+  */
+ function getUserIdFromParams(param) {
+   var userField = param;
+   var regex = new RegExp('[?&]' + userField + '(=([^&#]*)|&|#|$)');
+   var results = window.location.href.match(regex);
+ 
+   if (results && results[2]) {
+     return decodeURIComponent(results[2].replace(/\+/g, ' '));
+   } else {
+     return null;
+   }
  }
  
- /*
-  * Licensed to the Apache Software Foundation (ASF) under one or more
-  * contributor license agreements.  See the NOTICE file distributed with
-  * this work for additional information regarding copyright ownership.
-  * The ASF licenses this file to You under the Apache License, Version 2.0
-  * (the "License"); you may not use this file except in compliance with
-  * the License.  You may obtain a copy of the License at
-  *
-  *   http://www.apache.org/licenses/LICENSE-2.0
-  *
-  * Unless required by applicable law or agreed to in writing, software
-  * distributed under the License is distributed on an "AS IS" BASIS,
-  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  * See the License for the specific language governing permissions and
-  * limitations under the License.
-  */
- 
- // browser is defined in firefox, but not in chrome. In chrome, they use
- // the 'chrome' global instead. Let's map it to browser so we don't have
- // to have if-conditions all over the place.
- 
- var browser = browser || chrome;
+ /*
+  * Licensed to the Apache Software Foundation (ASF) under one or more
+  * contributor license agreements.  See the NOTICE file distributed with
+  * this work for additional information regarding copyright ownership.
+  * The ASF licenses this file to You under the Apache License, Version 2.0
+  * (the "License"); you may not use this file except in compliance with
+  * the License.  You may obtain a copy of the License at
+  * 
+  *   http://www.apache.org/licenses/LICENSE-2.0
+  * 
+  * Unless required by applicable law or agreed to in writing, software
+  * distributed under the License is distributed on an "AS IS" BASIS,
+  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  * See the License for the specific language governing permissions and
+  * limitations under the License.
+  */
+ 
+ var logs;
+ var config;
+ 
+ // Interval Logging Globals
+ var intervalID;
+ var intervalType;
+ var intervalPath;
+ var intervalTimer;
+ var intervalCounter;
+ var intervalLog;
+ 
+ var filterHandler = null;
+ var mapHandler = null;
+ 
+ /**
+  * Assigns a handler to filter logs out of the queue.
+  * @param  {Function} callback The handler to invoke when logging.
+  */
+ function setLogFilter(callback) {
+   filterHandler = callback;
+ }
+ 
+ 
+ /**
+  * Assigns the config and log container to be used by the logging functions.
+  * @param  {Array} newLogs   Log container.
+  * @param  {Object} newConfig Configuration to use while logging.
+  */
+ function initPackager(newLogs, newConfig) {
+   logs = newLogs;
+   config = newConfig;
+   filterHandler = null;
+   mapHandler = null;
+   intervalID = null;
+   intervalType = null;
+   intervalPath = null;
+   intervalTimer = null;
+   intervalCounter = 0;
+   intervalLog = null;
+ }
+ 
+ /**
+  * Transforms the provided event into a log and appends it to the log container.
+  * @param  {Object} e         The event to be logged.
+  * @param  {Function} detailFcn The function to extract additional log parameters from the event.
+  * @return {boolean}           Whether the event was logged.
+  */
+ function packageLog(e, detailFcn) {
+   if (!config.on) {
+     return false;
+   }
+ 
+   var details = null;
+   if (detailFcn) {
+     details = detailFcn(e);
+   }
+ 
+   var timeFields = extractTimeFields(
+     (e.timeStamp && e.timeStamp > 0) ? config.time(e.timeStamp) : Date.now()
+   );
+ 
+   var log = {
+     'target' : getSelector(e.target),
+     'path' : buildPath(e),
+     'pageUrl': window.location.href,
+     'pageTitle': document.title,
+     'pageReferrer': document.referrer,
+     'clientTime' : timeFields.milli,
+     'microTime' : timeFields.micro,
+     'location' : getLocation(e),
+     'type' : e.type,
+     'logType': 'raw',
+     'userAction' : true,
+     'details' : details,
+     'userId' : config.userId,
+     'toolVersion' : config.version,
+     'toolName' : config.toolName,
+     'useraleVersion': config.useraleVersion,
+     'sessionID': config.sessionID
+   };
+ 
+   if ((typeof filterHandler === 'function') && !filterHandler(log)) {
+     return false;
+   }
+ 
+   if (typeof mapHandler === 'function') {
+     log = mapHandler(log);
+   }
+ 
+   logs.push(log);
+ 
+   return true;
+ }
+ 
+ /**
+  * Extract the millisecond and microsecond portions of a timestamp.
+  * @param  {Number} timeStamp The timestamp to split into millisecond and microsecond fields.
+  * @return {Object}           An object containing the millisecond
+  *                            and microsecond portions of the timestamp.
+  */
+ function extractTimeFields(timeStamp) {
+   return {
+     milli: Math.floor(timeStamp),
+     micro: Number((timeStamp % 1).toFixed(3)),
+   };
+ }
+ 
+ /**
+  * Track intervals and gather details about it.
+  * @param {Object} e
+  * @return boolean
+  */
+ function packageIntervalLog(e) {
+     var target = getSelector(e.target);
+     var path = buildPath(e);
+     var type = e.type;
+     var timestamp = Math.floor((e.timeStamp && e.timeStamp > 0) ? config.time(e.timeStamp) : Date.now());
+ 
+     // Init - this should only happen once on initialization
+     if (intervalID == null) {
+         intervalID = target;
+         intervalType = type;
+         intervalPath = path;
+         intervalTimer = timestamp;
+         intervalCounter = 0;
+     }
+ 
+     if (intervalID !== target || intervalType !== type) {
+         // When to create log? On transition end
+         // @todo Possible for intervalLog to not be pushed in the event the interval never ends...
+ 
+         intervalLog = {
+             'target': intervalID,
+             'path': intervalPath,
+             'pageUrl': window.location.href,
+             'pageTitle': document.title,
+             'pageReferrer': document.referrer,
+             'count': intervalCounter,
+             'duration': timestamp - intervalTimer,  // microseconds
+             'startTime': intervalTimer,
+             'endTime': timestamp,
+             'type': intervalType,
+             'logType': 'interval',    
+             'targetChange': intervalID !== target,
+             'typeChange': intervalType !== type,
+             'userAction': false,
+             'userId': config.userId,
+             'toolVersion': config.version,
+             'toolName': config.toolName,
+             'useraleVersion': config.useraleVersion,
+             'sessionID': config.sessionID
+         };
+ 
+         if (typeof filterHandler === 'function' && !filterHandler(intervalLog)) {
+           return false;
+         }
+ 
+         if (typeof mapHandler === 'function') {
+           intervalLog = mapHandler(intervalLog);
+         }
+ 
+         logs.push(intervalLog);
+ 
+         // Reset
+         intervalID = target;
+         intervalType = type;
+         intervalPath = path;
+         intervalTimer = timestamp;
+         intervalCounter = 0;
+     }
+ 
+     // Interval is still occuring, just update counter
+     if (intervalID == target && intervalType == type) {
+         intervalCounter = intervalCounter + 1;
+     }
+ 
+     return true;
+ }
+ 
+ /**
+  * Extracts coordinate information from the event
+  * depending on a few browser quirks.
+  * @param  {Object} e The event to extract coordinate information from.
+  * @return {Object}   An object containing nullable x and y coordinates for the event.
+  */
+ function getLocation(e) {
+   if (e.pageX != null) {
+     return { 'x' : e.pageX, 'y' : e.pageY };
+   } else if (e.clientX != null) {
+     return { 'x' : document.documentElement.scrollLeft + e.clientX, 'y' : document.documentElement.scrollTop + e.clientY };
+   } else {
+     return { 'x' : null, 'y' : null };
+   }
+ }
+ 
+ /**
+  * Builds a string CSS selector from the provided element
+  * @param  {HTMLElement} ele The element from which the selector is built.
+  * @return {string}     The CSS selector for the element, or Unknown if it can't be determined.
+  */
+ function getSelector(ele) {
+   if (ele.localName) {
+     return ele.localName + (ele.id ? ('#' + ele.id) : '') + (ele.className ? ('.' + ele.className) : '');
+   } else if (ele.nodeName) {
+     return ele.nodeName + (ele.id ? ('#' + ele.id) : '') + (ele.className ? ('.' + ele.className) : '');
+   } else if (ele && ele.document && ele.location && ele.alert && ele.setInterval) {
+     return "Window";
+   } else {
+     return "Unknown";
+   }
+ }
+ 
+ /**
+  * Builds an array of elements from the provided event target, to the root element.
+  * @param  {Object} e Event from which the path should be built.
+  * @return {HTMLElement[]}   Array of elements, starting at the event target, ending at the root element.
+  */
+ function buildPath(e) {
+   var path = [];
+   if (e.path) {
+     path = e.path;
+   } else {
+     var ele = e.target;
+     while(ele) {
+       path.push(ele);
+       ele = ele.parentElement;
+     }
+   }
+ 
+   return selectorizePath(path);
+ }
+ 
+ /**
+  * Builds a CSS selector path from the provided list of elements.
+  * @param  {HTMLElement[]} path Array of HTMLElements from which the path should be built.
+  * @return {string[]}      Array of string CSS selectors.
+  */
+ function selectorizePath(path) {
+   var i = 0;
+   var pathEle;
+   var pathSelectors = [];
+   while (pathEle = path[i]) {
+     pathSelectors.push(getSelector(pathEle));
+     ++i;
+   }
+   return pathSelectors;
++>>>>>>> FLAGON-434
+ }
  
- // creates a Future for retrieval of the named keys
- // the value specified is the default value if one doesn't exist in the storage
- let store = browser.storage.local.get({
-   sessionId: null,
-   userAleHost: userAleHost,
-   userAleScript: userAleScript,
-   toolUser: toolUser,
-   toolName: toolName,
-   toolVersion: toolVersion,
- }, storeCallback);
-         
- function storeCallback(item) {
-   injectScript({
-     url: item.userAleHost,
-     userId: item.toolUser,
-     sessionID: item.sessionId,
-     toolName: item.toolName,
-     toolVersion: item.toolVersion
-   });
+ /*
+  * Licensed to the Apache Software Foundation (ASF) under one or more
+  * contributor license agreements.  See the NOTICE file distributed with
+  * this work for additional information regarding copyright ownership.
+  * The ASF licenses this file to You under the Apache License, Version 2.0
+  * (the "License"); you may not use this file except in compliance with
+  * the License.  You may obtain a copy of the License at
+  * 
+  *   http://www.apache.org/licenses/LICENSE-2.0
+  * 
+  * Unless required by applicable law or agreed to in writing, software
+  * distributed under the License is distributed on an "AS IS" BASIS,
+  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  * See the License for the specific language governing permissions and
+  * limitations under the License.
+  */
+ 
+ var sendIntervalId = null;
+ 
+ /**
+  * Initializes the log queue processors.
+  * @param  {Array} logs   Array of logs to append to.
+  * @param  {Object} config Configuration object to use when logging.
+  */
+ function initSender(logs, config) {
+   if (sendIntervalId !== null) {
+     clearInterval(sendIntervalId);
+   }
+ 
+   sendIntervalId = sendOnInterval(logs, config);
+   sendOnClose(logs, config);
+ }
+ 
+ /**
+  * Checks the provided log array on an interval, flushing the logs
+  * if the queue has reached the threshold specified by the provided config.
+  * @param  {Array} logs   Array of logs to read from.
+  * @param  {Object} config Configuration object to be read from.
+  * @return {Number}        The newly created interval id.
+  */
+ function sendOnInterval(logs, config) {
+   return setInterval(function() {
+     if (!config.on) {
+       return;
+     }
+ 
+     if (logs.length >= config.logCountThreshold) {
+       sendLogs(logs.slice(0), config.url, 0); // Send a copy
+       logs.splice(0); // Clear array reference (no reassignment)
+     }
+   }, config.transmitInterval);
+ }
+ 
+ /**
+  * Provides a simplified send function that can be called before events that would
+  * refresh page can resolve so that log queue ('logs) can be shipped immediately. This
+  * is different than sendOnClose because browser security practices prevent you from
+  * listening the process responsible for window navigation actions, in action (e.g., refresh;
+  * you can only detect, after the fact, the process responsible for the current window state.
+  * @param  {Array} logs   Array of logs to read from.
+  * @param  {Object} config Configuration object to be read from.
+  */
+ function sendOnRefresh(logs, config) {
+   if (!config.on) {
+     return;
+   }
+   if (logs.length > 0) {
+     sendLogs(logs, config.url, 1);
+   }
+ }
+ 
+ /**
+  * Attempts to flush the remaining logs when the window is closed.
+  * @param  {Array} logs   Array of logs to be flushed.
+  * @param  {Object} config Configuration object to be read from.
+  */
+ function sendOnClose(logs, config) {
+   if (!config.on) {
+     return;
+   }
+ 
+   if (navigator.sendBeacon) {
+     window.addEventListener('unload', function() {
+       navigator.sendBeacon(config.url, JSON.stringify(logs));
+     });
+   } else {
+     window.addEventListener('beforeunload', function() {
+       if (logs.length > 0) {
+         sendLogs(logs, config.url, 1);
+       }
+     });
+   }
+ }
+ 
+ /**
+  * Sends the provided array of logs to the specified url,
+  * retrying the request up to the specified number of retries.
+  * @param  {Array} logs    Array of logs to send.
+  * @param  {string} url     URL to send the POST request to.
+  * @param  {Number} retries Maximum number of attempts to send the logs.
+  */
+ function sendLogs(logs, url, retries) {
+   var req = new XMLHttpRequest();
+ 
+   var data = JSON.stringify(logs);
+ 
+   req.open('POST', url);
+   req.setRequestHeader('Content-type', 'application/json;charset=UTF-8');
+ 
+   req.onreadystatechange = function() {
+     if (req.readyState === 4 && req.status !== 200) {
+       if (retries > 0) {
+         sendLogs(logs, url, retries--);
+       }
+     }
+   };
+ 
+   req.send(data);
  }
  
- function queueLog(log) {
-   browser.runtime.sendMessage({ type: ADD_LOG, payload: log });
+ /*
+  * Licensed to the Apache Software Foundation (ASF) under one or more
+  * contributor license agreements.  See the NOTICE file distributed with
+  * this work for additional information regarding copyright ownership.
+  * The ASF licenses this file to You under the Apache License, Version 2.0
+  * (the "License"); you may not use this file except in compliance with
+  * the License.  You may obtain a copy of the License at
+  * 
+  *   http://www.apache.org/licenses/LICENSE-2.0
+  * 
+  * Unless required by applicable law or agreed to in writing, software
+  * distributed under the License is distributed on an "AS IS" BASIS,
+  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  * See the License for the specific language governing permissions and
+  * limitations under the License.
+  */
+ 
+ 
+ var events;
+ var bufferBools;
+ var bufferedEvents;
+ //@todo: Investigate drag events and their behavior
+ var intervalEvents = ['click', 'focus', 'blur', 'input', 'change', 'mouseover', 'submit'];
+ var refreshEvents;
+ var windowEvents = ['load', 'blur', 'focus'];
+ 
+ /**
+  * Maps an event to an object containing useful information.
+  * @param  {Object} e Event to extract data from
+  */
+ function extractMouseEvent(e) {
+   return {
+     'clicks' : e.detail,
+     'ctrl' : e.ctrlKey,
+     'alt' : e.altKey,
+     'shift' : e.shiftKey,
+     'meta' : e.metaKey
+   };
+ }
+ 
+ /**
+  * Defines the way information is extracted from various events.
+  * Also defines which events we will listen to.
+  * @param  {Object} config Configuration object to read from.
+  */
+ function defineDetails(config) {
+   // Events list
+   // Keys are event types
+   // Values are functions that return details object if applicable
+   events = {
+     'click' : extractMouseEvent,
+     'dblclick' : extractMouseEvent,
+     'mousedown' : extractMouseEvent,
+     'mouseup' : extractMouseEvent,
+     'focus' : null,
+     'blur' : null,
+     'input' : config.logDetails ? function(e) { return { 'value' : e.target.value }; } : null,
+     'change' : config.logDetails ? function(e) { return { 'value' : e.target.value }; } : null,
+     'dragstart' : null,
+     'dragend' : null,
+     'drag' : null,
+     'drop' : null,
+     'keydown' : config.logDetails ? function(e) { return { 'key' : e.keyCode, 'ctrl' : e.ctrlKey, 'alt' : e.altKey, 'shift' : e.shiftKey, 'meta' : e.metaKey }; } : null,
+     'mouseover' : null
+   };
+ 
+   bufferBools = {};
+   bufferedEvents = {
+     'wheel' : function(e) { return { 'x' : e.deltaX, 'y' : e.deltaY, 'z' : e.deltaZ }; },
+     'scroll' : function() { return { 'x' : window.scrollX, 'y' : window.scrollY }; },
+     'resize' : function() { return { 'width' : window.outerWidth, 'height' : window.outerHeight }; }
+   };
+ 
+   refreshEvents = {
+     'submit' : null
+   };
+ }
+ 
+ /**
+  * Hooks the event handlers for each event type of interest.
+  * @param  {Object} config Configuration object to use.
+  * @return {boolean}        Whether the operation succeeded
+  */
+ function attachHandlers(config) {
+   defineDetails(config);
+ 
+   Object.keys(events).forEach(function(ev) {
+     document.addEventListener(ev, function(e) {
+       packageLog(e, events[ev]);
+     }, true);
+   });
+ 
+   intervalEvents.forEach(function(ev) {
+     document.addEventListener(ev, function(e) {
+         packageIntervalLog(e);
+     }, true);
+   });
+ 
+   Object.keys(bufferedEvents).forEach(function(ev) {
+     bufferBools[ev] = true;
+ 
+     window.addEventListener(ev, function(e) {
+       if (bufferBools[ev]) {
+         bufferBools[ev] = false;
+         packageLog(e, bufferedEvents[ev]);
+         setTimeout(function() { bufferBools[ev] = true; }, config.resolution);
+       }
+     }, true);
+   });
+ 
+   Object.keys(refreshEvents).forEach(function(ev) {
+     document.addEventListener(ev, function(e) {
+       packageLog(e, events[ev]);
+       sendOnRefresh(logs,config);
+     }, true);
+   });
+ 
+   windowEvents.forEach(function(ev) {
+     window.addEventListener(ev, function(e) {
+       packageLog(e, function() { return { 'window' : true }; });
+     }, true);
+   });
+ 
+   return true;
  }
  
++<<<<<<< HEAD
 +function injectScript(config) {
 +  options(config);
 +//  start();  not necessary given that autostart in place, and option is masked from WebExt users
 +  setLogFilter(function (log) {
 +    queueLog(Object.assign({}, log, {
 +      pageUrl: document.location.href,
 +    }));
 +    return false;
 +  });
++=======
+ /*
+  * Licensed to the Apache Software Foundation (ASF) under one or more
+  * contributor license agreements.  See the NOTICE file distributed with
+  * this work for additional information regarding copyright ownership.
+  * The ASF licenses this file to You under the Apache License, Version 2.0
+  * (the "License"); you may not use this file except in compliance with
+  * the License.  You may obtain a copy of the License at
+  * 
+  *   http://www.apache.org/licenses/LICENSE-2.0
+  * 
+  * Unless required by applicable law or agreed to in writing, software
+  * distributed under the License is distributed on an "AS IS" BASIS,
+  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  * See the License for the specific language governing permissions and
+  * limitations under the License.
+  */
+ 
+ var config$1 = {};
+ var logs$1 = [];
+ var started = false;
+ 
+ // Start up Userale
+ config$1.on = false;
+ config$1.useraleVersion = version;
+ 
+ configure(config$1, getInitialSettings());
+ initPackager(logs$1, config$1);
+ 
+ if (config$1.autostart) {
+   setup(config$1);
+ }
+ 
+ /**
+  * Hooks the global event listener, and starts up the
+  * logging interval.
+  * @param  {Object} config Configuration settings for the logger
+  */
+ function setup(config) {
+   if (!started) {
+     setTimeout(function() {
+       var state = document.readyState;
+ 
+       if (state === 'interactive' || state === 'complete') {
+         attachHandlers(config);
+         initSender(logs$1, config);
+         started = config.on = true;
+       } else {
+         setup(config);
+       }
+     }, 100);
+   }
+ }
+ 
+ /**
+  * Updates the current configuration
+  * object with the provided values.
+  * @param  {Object} newConfig The configuration options to use.
+  * @return {Object}           Returns the updated configuration.
+  */
+ function options(newConfig) {
+   if (newConfig !== undefined) {
+     configure(config$1, newConfig);
+   }
+ 
+   return config$1;
++>>>>>>> FLAGON-434
  }
  
- browser.runtime.onMessage.addListener(function (message) {
-   if (message.type === CONFIG_CHANGE) {
-     options({
-       url: message.payload.userAleHost,
-       userId: message.payload.toolUser,
-       toolName: message.payload.toolName,
-       toolVersion: message.payload.toolVersion
-     });
-   }
- });
- 
- /*
-  eslint-enable
+ /*
+  * Licensed to the Apache Software Foundation (ASF) under one or more
+  * contributor license agreements.  See the NOTICE file distributed with
+  * this work for additional information regarding copyright ownership.
+  * The ASF licenses this file to You under the Apache License, Version 2.0
+  * (the "License"); you may not use this file except in compliance with
+  * the License.  You may obtain a copy of the License at
+  *
+  *   http://www.apache.org/licenses/LICENSE-2.0
+  *
+  * Unless required by applicable law or agreed to in writing, software
+  * distributed under the License is distributed on an "AS IS" BASIS,
+  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  * See the License for the specific language governing permissions and
+  * limitations under the License.
+  */
+ 
+ // browser is defined in firefox, but not in chrome. In chrome, they use
+ // the 'chrome' global instead. Let's map it to browser so we don't have
+ // to have if-conditions all over the place.
+ 
+ var browser = browser || chrome;
+ 
+ // creates a Future for retrieval of the named keys
+ // the value specified is the default value if one doesn't exist in the storage
+ let store = browser.storage.local.get({
+   sessionId: null,
+   userAleHost: userAleHost,
+   userAleScript: userAleScript,
+   toolUser: toolUser,
+   toolName: toolName,
+   toolVersion: toolVersion,
+ }, storeCallback);
+         
+ function storeCallback(item) {
+   injectScript({
+     url: item.userAleHost,
+     userId: item.toolUser,
+     sessionID: item.sessionId,
+     toolName: item.toolName,
+     toolVersion: item.toolVersion
+   });
+ }
+ 
+ function queueLog(log) {
+   browser.runtime.sendMessage({ type: ADD_LOG, payload: log });
+ }
+ 
+ function injectScript(config) {
+   options(config);
+ //  start();  not necessary given that autostart in place, and option is masked from WebExt users
+   setLogFilter(function (log) {
+     queueLog(Object.assign({}, log, {
+       pageUrl: document.location.href,
+     }));
+     return false;
+   });
+ }
+ 
+ browser.runtime.onMessage.addListener(function (message) {
+   if (message.type === CONFIG_CHANGE) {
+     options({
+       url: message.payload.userAleHost,
+       userId: message.payload.toolUser,
+       toolName: message.payload.toolName,
+       toolVersion: message.payload.toolVersion
+     });
+   }
+ });
+ 
+ /*
+  eslint-enable
   */
diff --cc example/index.html
index 2aa7cf7,8c8cde3..b5c90a4
--- a/example/index.html
+++ b/example/index.html
@@@ -18,19 -18,30 +18,29 @@@ limitations under the License
  <head>
    <title>UserAleJS - Example Page</title>
    <script
--    src="file:///{your file path}/incubator-flagon-useralejs/build/userale-2.0.2.min.js"
++    src="file:///Users/jpoore/Documents/Apache_Flagon/test/incubator-flagon-useralejs/build/userale-2.0.2.min.js"
      data-url="http://localhost:8000/"
      data-user="example-user"
 -    data-log-details="true"
      data-version="2.0.2"
      data-tool="Apache UserALE.js Example"
    ></script>
 -<!--Try out the options function to change UserALE.js params!
++<!--Try out the options function to change UserALE.js params@
+   <script type="text/javascript">
+       const changeMe = "me";
+       window.userale.options({
+         "userId": changeMe,
+         "version": "4.2.0",
+         "sessionID": "42"
+       })
+   </script>
+ -->
 -<!--Try out a UserALE.js filter to eliminate the logs that you don't want!
 -  <script type="text/javascript">
 -  window.userale.filter(function (log) {
 -    var type_array = ['mouseup', 'mouseover', 'dblclick', 'blur', 'focus'];
 -    var logType_array = ['interval'];
 -    return !type_array.includes(log.type) && !logType_array.includes(log.logType);
 -  });
 +<!--Try out a UserALE.js filter!
 +    <script type="text/javascript">
 +    window.userale.filter(function (log) {
-       var type_array = ['mouseup', 'mouseover', 'dblclick', 'blur', 'focus']
-       var logType_array = ['interval']
++      var type_array = ['mouseup', 'mouseover', 'dblclick', 'blur', 'focus'];
++      var logType_array = ['interval'];
 +      return !type_array.includes(log.type) && !logType_array.includes(log.logType);
 +    });
    </script>
  -->
  </head>