diff --git a/core/Updates/2.7.0-b2.php b/core/Updates/2.7.0-b2.php
index 708fdd8ab4ebf08e50083f1a454b2b37693ec234..1f0f04d9e01199949f394c943413b7a57416410c 100644
--- a/core/Updates/2.7.0-b2.php
+++ b/core/Updates/2.7.0-b2.php
@@ -9,15 +9,27 @@
 
 namespace Piwik\Updates;
 
+use Piwik\Common;
+use Piwik\Updater;
 use Piwik\Updates;
 
 /**
  */
 class Updates_2_7_0_b2 extends Updates
 {
+    static function getSql()
+    {
+        return array(
+            'ALTER TABLE `' . Common::prefixTable('log_visit') . '`
+			    ADD `user_id` varchar(200) NULL AFTER `config_id`
+			   ' => array(1060),
+        );
+    }
 
     static function update()
     {
+        Updater::updateDatabase(__FILE__, self::getSql());
+
         $pluginManager = \Piwik\Plugin\Manager::getInstance();
 
         try {
diff --git a/js/piwik.js b/js/piwik.js
index ae14b1d0a85775896481db94358e92f28d885eea..85ba901fbda40c199d515112dd60374d628c760e 100644
--- a/js/piwik.js
+++ b/js/piwik.js
@@ -454,7 +454,7 @@ if (typeof JSON2 !== 'object') {
     enableTrackOnlyVisibleContent, trackContentInteraction, clearEnableTrackOnlyVisibleContent,
     trackVisibleContentImpressions, isTrackOnlyVisibleContentEnabled, port, isUrlToCurrentDomain,
     isNodeAuthorizedToTriggerInteraction, replaceHrefIfInternalLink, getConfigDownloadExtensions, disableLinkTracking,
-    substr, setAnyAttribute, wasContentTargetAttrReplaced
+    substr, setAnyAttribute, wasContentTargetAttrReplaced, max, abs
  */
 /*global _paq:true */
 /*members push */
@@ -1000,6 +1000,53 @@ if (typeof Piwik !== 'object') {
             return title;
         }
 
+        // Polyfill for IndexOf for IE6-IE8
+        function indexOfArray(theArray, searchElement)
+        {
+            if (theArray && theArray.indexOf) {
+                return theArray.indexOf(searchElement);
+            }
+
+            // 1. Let O be the result of calling ToObject passing
+            //    the this value as the argument.
+            if (!isDefined(theArray) || theArray === null) {
+                return -1;
+            }
+
+            if (!theArray.length) {
+                return -1;
+            }
+
+            var len = theArray.length;
+
+            if (len === 0) {
+                return -1;
+            }
+
+            var k = 0;
+
+            // 9. Repeat, while k < len
+            while (k < len) {
+                // a. Let Pk be ToString(k).
+                //   This is implicit for LHS operands of the in operator
+                // b. Let kPresent be the result of calling the
+                //    HasProperty internal method of O with argument Pk.
+                //   This step can be combined with c
+                // c. If kPresent is true, then
+                //    i.  Let elementK be the result of calling the Get
+                //        internal method of O with the argument ToString(k).
+                //   ii.  Let same be the result of applying the
+                //        Strict Equality Comparison Algorithm to
+                //        searchElement and elementK.
+                //  iii.  If same is true, return k.
+                if (theArray[k] === searchElement) {
+                    return k;
+                }
+                k++;
+            }
+            return -1;
+        }
+
         /************************************************************
          * Element Visiblility
          ************************************************************/
@@ -1196,8 +1243,8 @@ if (typeof Piwik !== 'object') {
                         return 0;
                     }
 
-                    var index1 = copy.indexOf(n1);
-                    var index2 = copy.indexOf(n2);
+                    var index1 = indexOfArray(copy, n1);
+                    var index2 = indexOfArray(copy, n2);
 
                     if (index1 === index2) {
                         return 0;
@@ -1296,7 +1343,7 @@ if (typeof Piwik !== 'object') {
             {
                 if (node && className && node.className) {
                     var classes = node.className.split(' ');
-                    if (-1 !== classes.indexOf(className)) {
+                    if (-1 !== indexOfArray(classes, className)) {
                         return true;
                     }
                 }
@@ -1419,7 +1466,7 @@ if (typeof Piwik !== 'object') {
 
                 var elementName      = String(node.nodeName).toLowerCase();
                 var linkElementNames = ['a', 'area'];
-                var pos = linkElementNames.indexOf(elementName);
+                var pos = indexOfArray(linkElementNames, elementName);
 
                 return pos !== -1;
             },
@@ -1683,7 +1730,7 @@ if (typeof Piwik !== 'object') {
                 var mediaElements = ['img', 'embed', 'video', 'audio'];
                 var elementName   = node.nodeName.toLowerCase();
 
-                if (-1 !== mediaElements.indexOf(elementName) &&
+                if (-1 !== indexOfArray(mediaElements, elementName) &&
                     query.findFirstNodeHavingAttributeWithValue(node, 'src')) {
 
                     var sourceNode = query.findFirstNodeHavingAttributeWithValue(node, 'src');
diff --git a/misc/internal-docs/content-tracking.md b/misc/internal-docs/content-tracking.md
index 154419957bd66149acdeaf64277f81c5a8389768..a9bc016d42084437a7cdf8bd68b0a79aa5018a7f 100644
--- a/misc/internal-docs/content-tracking.md
+++ b/misc/internal-docs/content-tracking.md
@@ -433,7 +433,7 @@ Nothing special here I think. We would probably automatically detect the type of
   * Overlay session should not trigger a content impression
 * Cache allowed site urls for redirects
 * Test scroll event in ie9, ie10, ie11, opera
-* Run JS tests  in ff3, ie7, ie8, ie9, ie11, android, iphone, ms phone
+* Run JS tests  in ff3, ie9, ie11, android, iphone, ms phone
 * Show images on hover in report
 * When a user clicks on an interaction, we should check whether we have already tracked the impression as the content is visible now. If not tracked before, we should track the impression as well
   * There can be a scroll or timer event that detects the same content became visible as well. This would not be a problem since we do not track same content block twice
diff --git a/tests/javascript/index.php b/tests/javascript/index.php
index a67f40b526bd2c1ddab34c34d901e0c9a4e9bc97..08cd90cfee0d83eb7e118bb03c0a15b7698085fc 100644
--- a/tests/javascript/index.php
+++ b/tests/javascript/index.php
@@ -99,6 +99,52 @@ function _s(selector) { // select node within content test scope
  }
 }
 
+ // Polyfill for IndexOf for IE6-IE8
+ function indexOfArray(theArray, searchElement)
+ {
+     if (theArray && theArray.indexOf) {
+         return theArray.indexOf(searchElement);
+     }
+
+     // 1. Let O be the result of calling ToObject passing
+     //    the this value as the argument.
+     if (!isDefined(theArray) || theArray === null) {
+         return -1;
+     }
+
+     if (!theArray.length) {
+         return -1;
+     }
+
+     var len = theArray.length;
+
+     if (len === 0) {
+         return -1;
+     }
+
+     var k = 0;
+
+     // 9. Repeat, while k < len
+     while (k < len) {
+         // a. Let Pk be ToString(k).
+         //   This is implicit for LHS operands of the in operator
+         // b. Let kPresent be the result of calling the
+         //    HasProperty internal method of O with argument Pk.
+         //   This step can be combined with c
+         // c. If kPresent is true, then
+         //    i.  Let elementK be the result of calling the Get
+         //        internal method of O with the argument ToString(k).
+         //   ii.  Let same be the result of applying the
+         //        Strict Equality Comparison Algorithm to
+         //        searchElement and elementK.
+         //  iii.  If same is true, return k.
+         if (theArray[k] === searchElement) {
+             return k;
+         }
+         k++;
+     }
+     return -1;
+ }
  function getOrigin()
  {
      if (window.location.origin) {
@@ -672,7 +718,7 @@ function PiwikTest() {
         ok($.isArray(actual), 'htmlCollectionToArray, should convert to array');
         ok(actual.length === htmlCollection.length, 'htmlCollectionToArray should have same amount of elements as before');
         ok(actual.length > 10, 'htmlCollectionToArray, just make sure there are many a elements found. otherwise test is useless');
-        ok(-1 !== actual.indexOf(_e('click1')), 'htmlCollectionToArray, random check to make sure it contains a link');
+        ok(-1 !== indexOfArray(actual, _e('click1')), 'htmlCollectionToArray, random check to make sure it contains a link');
 
 
         actual = query.isLinkElement();
@@ -708,11 +754,11 @@ function PiwikTest() {
 
         actual = query.find('[href]');
         ok(actual.length > 10, "find, should find many elements by attribute");
-        ok(-1 !== actual.indexOf(_e('click1')), 'find, random check to make sure it contains a link');
+        ok(-1 !== indexOfArray(actual, _e('click1')), 'find, random check to make sure it contains a link');
 
         actual = query.find('.clicktest');
         ok(actual.length === 8, "find, should find many elements by class");
-        ok(-1 !== actual.indexOf(_e('click1')), 'find, random check to make sure it contains a link');
+        ok(-1 !== indexOfArray(actual, _e('click1')), 'find, random check to make sure it contains a link');
 
 
 
@@ -749,7 +795,7 @@ function PiwikTest() {
 
         actual = query.findNodesByTagName(document.body, 'a');
         ok(actual.length > 10, "findNodesByTagName, find many, even nested ones");
-        ok(actual.indexOf(_e('click1')), "findNodesByTagName, just a random test to make sure it actually contains a link");
+        ok(indexOfArray(actual, _e('click1')), "findNodesByTagName, just a random test to make sure it actually contains a link");
     });
 
     test("contentFindContentBlock", function() {