[
  {
    "path": "License.md",
    "content": "BSD 3-Clause License\n\nCopyright (c) 2017, \nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this\n  list of conditions and the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright notice,\n  this list of conditions and the following disclaimer in the documentation\n  and/or other materials provided with the distribution.\n\n* Neither the name of the copyright holder nor the names of its\n  contributors may be used to endorse or promote products derived from\n  this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
  },
  {
    "path": "README.md",
    "content": "# Introduction\nJavascript to detect the presence of behavior associated with ad blocking during delivery of a page.\n\n# Operation\nThe JavaScript (adblockDetector.js) has been tested to detect the behaviors associated with ad blocking in the following web browsers:\n- Google Chrome\n- Mozilla Firefox\n- Internet Explorer (8+)\n- Safari\n\nThe script does this by creating a set of DIVs that are likely to be hidden by browser-based ad blocking tools.  \n\nAdditional tactics that are not yet included in this script:\n- URL bait.  Allow the detection of network-based ad blocking.  \n- Dynamic bait modification.  Update DIV and URL attributes based on the existing blocking lists (Easylist and so on) to make detection more robust.  \n\n# Installation\nDownload the desired detection script and add it to your website. There are a few different ways to include JavaScript into HTML.  \n\n| Script Name        | Description    |\n| ------------- |:-------------:|\n| adblockDetector.js     | Adblocker detection script without Google Analytics module | \n| adblockDetectorWithGA.js     | Adblocker detection script with Google Analytics module | \n\n\nWith AdBlockDetectionWithGA.js you are asked to mention your GA tracking id into the script on line no 82. When you are referencing this script, it tracks certain events regarding AdBlock on user browser. You can view the details in the Google Analytics dashboard. Here is how to check whether user are using any adblock or not.\n\n###### Setting up Google Analytics\nFirstly, we would suggest you create a different GA-Tracking id so that it might not interfere with your pageviews. Follow below steps for GA on Use of Adblock. \n \n- Sign into your Google Analytics account -> Go to your site -> Go to “Reporting” tab -> click “User Explorer” under Audience.\n- Click on “Add new segment” -> “New Segment” -> Give Segment name (ex: ‘Adblock Detected’) -> Click on “conditions” under Advanced section.\n- Click on Sessions and select Users (You can create a different one for sessions too.) \n- Click on the first Drop Down -> Click on “Behavior” ->Select “Event Label”.\n- Click On the Text box: Type event label as below.\n- Event Label- “div hidden” – this will give you all users with Ad block enable/found.Now your one segment with Users who use ad block is ready. \n- Repeat all above steps with Below event label for users who do not use ad block. \n- Event Label- “div visible” –this will give you all users with ad block disabled/notfound.\n\nUnfortunately we have not figured out yet how to put it to dash board. So next time when you go to GA, you can go to User Explorer -> click Add new segment. And you will find the segments you previously created(i.e one for adblock Detected users and one for ad block NotDetected users.). You can select them and click on apply to see reported data.\n\nIt should look like below image.\n\n![alt text](https://s3.amazonaws.com/iab-tech-lab/images/ga.png \"GA User Explorer\")\n\n###### Inline\nThis is the recommended method of inclusion.  The functions contained in the chosen detection script should be included directly into the HTML of the parent frame.  \n\nDo this by wrapping the content of the selected code in script tags in the delivered HTML.  \n###### External Script File\nIt is possible to host the selected code on your web server as an independent file, and to reference this file from the delivered HTML.  \n\nIf you use an external script file, it can be blocked by ad blockers.  Using a different name for the file will reduce the probability that it will be blocked by generic filters. \n\n###### Other Methods\nIt is possible to integrate the functions from the selected code into an existing script library, hosted as an external script file.  Doing this may result in reduced site functionality for visitors using ad blockers that are trying to avoid detection, if the ad blockers block the entire external script file.  \n\n# Configuration\n@prop flags\n\n| Option        | Type           | Description  |\n| ------------- |:-------------:| :-----:|\n| debug     | Boolean | Indicates additional debug output should be printed to console |\n| found      | String (@function)      |   Function to fire if adblock is detected |\n| notfound | String (@function)      |    Function to fire if adblock is not detected.  Note that this will fire each time adblock is not detected, and should provide input to action taken only after “complete” is detected. |\n| complete     | String (@function) | Function to fire once testing is complete. |\n\nThe test result (boolean) is included as a parameter to callback\nexample:  \n```javascript\nwindow.adblockDetector.init(\n        {\n          found: function(){ ...},\n          notFound: function(){...}\n        }\n      );\n```\n\n# Usage\nAdd the below code in the HTML page. \n```javascript\n<script src=\"./adblockDetector.js\"></script>\n\t<script>\n\t// Configure the adblock detector\n\t(function(){\n\t\tvar enabledEl = document.getElementById('adb-enabled');\n\t\tvar disabledEl = document.getElementById('adb-not-enabled');\n\t\tfunction adBlockDetected() {\n\t\t\tenabledEl.style.display = 'block';\n\t\t\tdisabledEl.style.display = 'none';\n\t\t}\n\t\tfunction adBlockNotDetected() {\n\t\t\tdisabledEl.style.display = 'block';\n\t\t\tenabledEl.style.display = 'none';\n\t\t}\n\t\t\n\t\tif(typeof window.adblockDetector === 'undefined') {\n\t\t\tadBlockDetected();\n\t\t} else {\n\t\t\twindow.adblockDetector.init(\n\t\t\t\t{\n\t\t\t\t\tdebug: true,\n\t\t\t\t\tfound: function(){\n\t\t\t\t\t\tadBlockDetected();\n\t\t\t\t\t},\n\t\t\t\t\tnotFound: function(){\n\t\t\t\t\t\tadBlockNotDetected();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t);\n\t\t}\n\t}());\n\t</script>\n```\n \nAdd below code in the body of the HTML page\n```html\n<div class=\"center\">\n<h5 class=\"bg-success\" id=\"adb-not-enabled\" style=\"display: none;\">AdBlock is disabled</h5>\n<h5 class=\"bg-danger\" id=\"adb-enabled\" style=\"display: none;\">AdBlock is enabled</h5>\n</div>\n```\n\n# Contributing\nFork it!\nCreate your feature branch: git checkout -b my-new-feature\nCommit your changes: git commit -am 'Add some feature'\nPush to the branch: git push origin my-new-feature\nSubmit a pull request\n\n# FAQ\n- The script will not work locally. The page should get served from the server via http\n- Currently the “baits” or “honey pods” used in the Javascript are hardcoded @ #218. If you want to update the file with new baits update the line #218\n- Use the sample file test.html find in the repository. Host the file on HTTP server eg. apache server and request the file in browser via http with adblocker on/off.\n"
  },
  {
    "path": "adblockDetector.js",
    "content": "// ===============================================\n// AdBlock detector\n//\n// Attempts to detect the presence of Ad Blocker software and notify listener of its existence.\n// Copyright (c) 2017 IAB\n//\n// The BSD-3 License\n// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:\n// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.\n// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.\n// 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.\n// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n// ===============================================\n\n/**\n* @name window.adblockDetector\n*\n* IAB Adblock detector.\n* Usage: window.adblockDetector.init(options);\n*\n* Options object settings\n*\n*\t@prop debug:  boolean\n*         Flag to indicate additional debug output should be printed to console\n*\n*\t@prop found: @function\n*         Callback function to fire if adblock is detected\n*\n*\t@prop notfound: @function\n*         Callback function to fire if adblock is not detected.\n*         NOTE: this function may fire multiple times and give false negative\n*         responses during a test until adblock is successfully detected.\n*\n*\t@prop complete: @function\n*         Callback function to fire once a round of testing is complete.\n*         The test result (boolean) is included as a parameter to callback\n*\n* example: \twindow.adblockDetector.init(\n\t\t\t\t{\n\t\t\t\t\tfound: function(){ ...},\n \t\t\t\t\tnotFound: function(){...}\n\t\t\t\t}\n\t\t\t);\n*\n*\n*/\n\n\"use strict\";\n(function(win) {\n\t\n\tvar version = '1.0';\n\t\n\tvar ofs = 'offset', cl = 'client';\n\tvar noop = function(){};\n\t\n\tvar testedOnce = false;\n\tvar testExecuting = false;\n\t\n\tvar isOldIEevents = (win.addEventListener === undefined);\n\t\n\t/**\n\t* Options set with default options initialized\n\t*\n\t*/\t\n\tvar _options = {\n\t\tloopDelay: 50,\n\t\tmaxLoop: 5,\n\t\tdebug: true,\n\t\tfound: noop, \t\t\t\t\t// function to fire when adblock detected\n\t\tnotfound: noop, \t\t\t\t// function to fire if adblock not detected after testing\n\t\tcomplete: noop  \t\t\t\t// function to fire after testing completes, passing result as parameter\n\t}\n\t\n\tfunction parseAsJson(data){\n\t\tvar result, fnData;\n\t\ttry{\n\t\t\tresult = JSON.parse(data);\n\t\t}\n\t\tcatch(ex){\n\t\t\ttry{\n\t\t\t\tfnData = new Function(\"return \" + data);\n\t\t\t\tresult = fnData();\n\t\t\t}\n\t\t\tcatch(ex){\n\t\t\t\tlog('Failed secondary JSON parse', true);\n\t\t\t}\t\t\t\n\t\t}\n\t\t\n\t\treturn result;\n\t}\n\t\n\t/**\n\t* Ajax helper object to download external scripts.\n\t* Initialize object with an options object\n\t* Ex:\n\t  {\n\t\t  url : 'http://example.org/url_to_download',\n\t\t  method: 'POST|GET',\n\t\t  success: callback_function,\n\t\t  fail:  callback_function\n\t  }\t\t\n\t*/\n\tvar AjaxHelper = function(opts){\n\t\tvar xhr = new XMLHttpRequest();\n\t\t\n\t\tthis.success = opts.success || noop;\n\t\tthis.fail = opts.fail || noop;\n\t\tvar me = this;\n\t\t\n\t\tvar method = opts.method || 'get';\n\t\t\n\t\t/**\n\t\t* Abort the request\n\t\t*/\n\t\tthis.abort = function(){\n\t\t\ttry{\n\t\t\t\txhr.abort();\n\t\t\t}\n\t\t\tcatch(ex){\n\t\t\t}\n\t\t}\n\t\t\n\t\tfunction stateChange(vals){\n\t\t\tif(xhr.readyState == 4){\n\t\t\t\tif(xhr.status == 200){\n\t\t\t\t\tme.success(xhr.response);\n\t\t\t\t}\n\t\t\t\telse{\n\t\t\t\t\t// failed\n\t\t\t\t\tme.fail(xhr.status);\n\t\t\t\t}\t\t\t\t\n\t\t\t}\n\t\t}\n\t\t\n\t\txhr.onreadystatechange = stateChange;\n\t\t\n\t\tfunction start(){\n\t\t\txhr.open(method, opts.url, true);\n\t\t\txhr.send();\n\t\t}\n\t\t\n\t\tstart();\n\t}\n\t\n\t/**\n\t* Object tracking the various block lists\n\t*/\n\tvar BlockListTracker = function(){\n\t\tvar me = this;\n\t\tvar externalBlocklistData = {};\n\t\t\n\t\t/**\n\t\t* Add a new external URL to track\n\t\t*/\n\t\tthis.addUrl = function(url){\n\t\t\texternalBlocklistData[url] = {\n\t\t\t\turl: url,\n\t\t\t\tstate: 'pending',\n\t\t\t\tformat: null,\n\t\t\t\tdata: null,\n\t\t\t\tresult: null\n\t\t\t}\n\t\t\t\n\t\t\treturn externalBlocklistData[url];\n\t\t}\n\t\t\n\t\t/**\n\t\t* Loads a block list definition\n\t\t*/\n\t\tthis.setResult = function(urlKey, state, data){\n\t\t\tvar obj = externalBlocklistData[urlKey];\n\t\t\tif(obj == null){\n\t\t\t\tobj = this.addUrl(urlKey);\n\t\t\t}\n\t\t\t\n\t\t\tobj.state = state;\n\t\t\tif(data == null){\n\t\t\t\tobj.result = null;\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tif(typeof data === 'string'){\n\t\t\t\ttry{\n\t\t\t\t\tdata = parseAsJson(data);\n\t\t\t\t\tobj.format = 'json';\n\t\t\t\t}\n\t\t\t\tcatch(ex){\n\t\t\t\t\tobj.format = 'easylist';\n\t\t\t\t\t// parseEasyList(data);\n\t\t\t\t}\n\t\t\t}\n\t\t\tobj.data = data;\n\t\t\t\n\t\t\treturn obj;\n\t\t}\n\t\t\n\t}\n\t\n\tvar listeners = []; // event response listeners\n\tvar baitNode = null;\n\tvar quickBait = {\n\t\tcssClass: 'pub_300x250 pub_300x250m pub_728x90 text-ad textAd text_ad text_ads text-ads text-ad-links'\t\t\n\t};\n\tvar baitTriggers = {\n\t\tnullProps: [ofs + 'Parent'],\n\t\tzeroProps: []\n\t};\n\t\n\tbaitTriggers.zeroProps = [\n\t\tofs +'Height', ofs +'Left', ofs +'Top', ofs +'Width', ofs +'Height',\n\t\tcl + 'Height', cl + 'Width'\n\t];\n\t\n\t// result object\n\tvar exeResult = {\n\t\tquick: null,\n\t\tremote: null\n\t};\n\t\n\tvar findResult = null; // result of test for ad blocker\n\t\n\tvar timerIds = {\n\t\ttest: 0,\n\t\tdownload: 0\n\t};\n\t\n\tfunction isFunc(fn){\n\t\treturn typeof(fn) == 'function';\n\t}\n\t\n\t/**\n\t* Make a DOM element\n\t*/\n\tfunction makeEl(tag, attributes){\n\t\tvar k, v, el, attr = attributes;\n\t\tvar d = document;\n\t\t\n\t\tel = d.createElement(tag);\n\t\t\n\t\tif(attr){\n\t\t\tfor(k in attr){\n\t\t\t\tif(attr.hasOwnProperty(k)){\n\t\t\t\t\tel.setAttribute(k, attr[k]);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\treturn el;\n\t}\n\t\n\tfunction attachEventListener(dom, eventName, handler){\n\t\tif(isOldIEevents){\n\t\t\tdom.attachEvent('on' + eventName, handler);\n\t\t}\n\t\telse{\n\t\t\tdom.addEventListener(eventName, handler, false);\n\t\t}\n\t}\n\t\n\tfunction log(message, isError){\n\t\tif(!_options.debug && !isError){\n\t\t\treturn;\n\t\t}\n\t\tif(win.console && win.console.log){\n\t\t\tif(isError){\n\t\t\t\tconsole.error('[ABD] ' + message);\n\t\t\t}\n\t\t\telse{\n\t\t\t\tconsole.log('[ABD] ' + message);\n\t\t\t}\n\t\t}\n\t}\n\t\n\tvar ajaxDownloads = [];\n\t\n\t/**\n\t* Load and execute the URL inside a closure function\n\t*/\n\tfunction loadExecuteUrl(url){\n\t\tvar ajax, result;\n\t\t\n\t\tblockLists.addUrl(url);\n\t\t// setup call for remote list\n\t\tajax = new AjaxHelper(\n\t\t\t{ \n\t\t\t\turl: url,\n\t\t\t\tsuccess: function(data){\n\t\t\t\t\tlog('downloaded file ' + url); // todo - parse and store until use\n\t\t\t\t\tresult = blockLists.setResult(url, 'success', data);\n\t\t\t\t\ttry{\n\t\t\t\t\t\tvar intervalId = 0,\n\t\t\t\t\t\t\tretryCount = 0;\n\t\t\t\t\t\t\n\t\t\t\t\t\tvar tryExecuteTest = function(listData){\n\t\t\t\t\t\t\tif(!testExecuting){\n\t\t\t\t\t\t\t\tbeginTest(listData, true);\n\t\t\t\t\t\t\t\treturn true;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\treturn false;\t\t\t\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\tif(findResult == true){\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\tif(tryExecuteTest(result.data)){\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse{\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tlog('Pause before test execution');\n\t\t\t\t\t\t\tintervalId = setInterval(function(){\n\t\t\t\t\t\t\t\tif(tryExecuteTest(result.data) || retryCount++ > 5){\n\t\t\t\t\t\t\t\t\tclearInterval(intervalId);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}, 250);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tcatch(ex){\n\t\t\t\t\t\tlog(ex.message + ' url: ' + url, true);\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\tfail: function(status){\n\t\t\t\t\tlog(status, true);\n\t\t\t\t\tblockLists.setResult(url, 'error', null);\n\t\t\t\t}\n\t\t\t});\n\t\t\t\n\t\tajaxDownloads.push(ajax);\n\t}\n\t\n\t\n\t/**\n\t* Fetch the external lists and initiate the tests\n\t*/\n\tfunction fetchRemoteLists(){\n\t\tvar i, url;\n\t\tvar opts = _options;\n\t\t\n\t\tfor(i=0;i<opts.blockLists.length;i++){\n\t\t\turl = opts.blockLists[i];\n\t\t\tloadExecuteUrl(url);\t\t\t\n\t\t}\n\t}\n\t\n\tfunction cancelRemoteDownloads(){\n\t\tvar i, aj;\n\t\t\n\t\tfor(i=ajaxDownloads.length-1;i >= 0;i--){\n\t\t\taj = ajaxDownloads.pop();\n\t\t\taj.abort();\n\t\t}\t\t\n\t}\n\t\n\t\n\t// =============================================================================\n\t/**\n\t* Begin execution of the test\n\t*/\n\tfunction beginTest(bait){\n\t\tlog('start beginTest');\n\t\tif(findResult == true){\n\t\t\treturn; // we found it. don't continue executing\n\t\t}\n\t\ttestExecuting = true;\n\t\tcastBait(bait);\n\t\t\n\t\texeResult.quick = 'testing';\n\t\t\n\t\ttimerIds.test = setTimeout(\n\t\t\tfunction(){ reelIn(bait, 1); },\n\t\t\t5);\n\t}\n\t\n\t/**\n\t* Create the bait node to see how the browser page reacts\n\t*/\n\tfunction castBait(bait){\n\t\tvar i, d = document, b = d.body;\n\t\tvar t;\n\t\tvar baitStyle = 'width: 1px !important; height: 1px !important; position: absolute !important; left: -10000px !important; top: -1000px !important;'\n\t\t\n\t\tif(bait == null || typeof(bait) == 'string'){\n\t\t\tlog('invalid bait being cast');\n\t\t\treturn;\n\t\t}\n\t\t\n\t\tif(bait.style != null){\n\t\t\tbaitStyle += bait.style;\n\t\t}\n\t\t\n\t\tbaitNode = makeEl('div', {\n\t\t\t'class': bait.cssClass,\n\t\t\t'style': baitStyle\n\t\t});\n\t\t\n\t\tlog('adding bait node to DOM');\n\n\t\tb.appendChild(baitNode);\n\t\t\n\t\t// touch these properties\n\t\tfor(i=0;i<baitTriggers.nullProps.length;i++){\n\t\t\tt = baitNode[baitTriggers.nullProps[i]];\n\t\t}\n\t\tfor(i=0;i<baitTriggers.zeroProps.length;i++){\n\t\t\tt = baitNode[baitTriggers.zeroProps[i]];\n\t\t}\n\t}\n\t\n\t/**\n\t* Run tests to see if browser has taken the bait and blocked the bait element\n\t*/\n\tfunction reelIn(bait, attemptNum){\n\t\tvar i, k, v;\n\t\tvar body = document.body;\n\t\tvar found = false;\n\t\t\n\t\tif(baitNode == null){\n\t\t\tlog('recast bait');\n\t\t\tcastBait(bait || quickBait);\n\t\t}\n\n\t\tif(typeof(bait) == 'string'){\n\t\t\tlog('invalid bait used', true);\n\t\t\tif(clearBaitNode()){\n\t\t\t\tsetTimeout(function(){\n\t\t\t\t\ttestExecuting = false;\n\t\t\t\t}, 5);\n\t\t\t}\n\n\t\t\treturn;\n\t\t}\n\n\t\tif(timerIds.test > 0){\n\t\t\tclearTimeout(timerIds.test);\n\t\t\ttimerIds.test = 0;\n\t\t}\n\t\t\n\t\t// test for issues\n\n\t\tif(body.getAttribute('abp') !== null){\n\t\t\tlog('found adblock body attribute');\n\t\t\tfound = true;\n\t\t}\n\n\t\tfor(i=0;i<baitTriggers.nullProps.length;i++){\n\t\t\tif(baitNode[baitTriggers.nullProps[i]] == null){\n\t\t\t\tif(attemptNum>4)\n\t\t\t\tfound = true;\n\t\t\t\tlog('found adblock null attr: ' + baitTriggers.nullProps[i]);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif(found == true){\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\t\n\t\tfor(i=0;i<baitTriggers.zeroProps.length;i++){\n\t\t\tif(found == true){\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif(baitNode[baitTriggers.zeroProps[i]] == 0){\n\t\t\t\tif(attemptNum>4)\n\t\t\t\tfound = true;\n\t\t\t\tlog('found adblock zero attr: ' + baitTriggers.zeroProps[i]);\n\t\t\t}\n\t\t}\n\n\t\tif(window.getComputedStyle !== undefined) {\n\t\t\tvar baitTemp = window.getComputedStyle(baitNode, null);\n\t\t\tif(baitTemp.getPropertyValue('display') == 'none'\n\t\t\t|| baitTemp.getPropertyValue('visibility') == 'hidden') {\n\t\t\t\tif(attemptNum>4)\n\t\t\t\tfound = true;\n\t\t\t\tlog('found adblock computedStyle indicator');\n\t\t\t}\n\t\t}\n\n\t\ttestedOnce = true;\n\t\t\n\t\tif(found || attemptNum++ >= _options.maxLoop){\n\t\t\tfindResult = found;\n\t\t\tlog('exiting test loop - value: ' + findResult);\n\t\t\tnotifyListeners();\n\t\t\tif(clearBaitNode()){\n\t\t\t\tsetTimeout(function(){\n\t\t\t\t\ttestExecuting = false;\n\t\t\t\t}, 5);\n\t\t\t}\n\t\t}\n\t\telse{\n\t\t\ttimerIds.test = setTimeout(function(){\n\t\t\t\treelIn(bait, attemptNum);\n\t\t\t}, _options.loopDelay);\n\t\t}\n\t}\n\t\n\tfunction clearBaitNode(){\n\t\tif(baitNode === null){\n\t\t\treturn true;\n\t\t}\n\t\t\n\t\ttry{\n\t\t\tif(isFunc(baitNode.remove)){\n\t\t\t\tbaitNode.remove();\n\t\t\t}\n\t\t\tdocument.body.removeChild(baitNode);\n\t\t}\n\t\tcatch(ex){\n\t\t}\n\t\tbaitNode = null;\n\t\t\n\t\treturn true;\t\t\n\t}\n\t\n\t/**\n\t* Halt the test and any pending timeouts\n\t*/\n\tfunction stopFishing(){\n\t\tif(timerIds.test > 0){\n\t\t\tclearTimeout(timerIds.test);\n\t\t}\n\t\tif(timerIds.download > 0){\n\t\t\tclearTimeout(timerIds.download);\n\t\t}\n\t\t\n\t\tcancelRemoteDownloads();\n\t\t\n\t\tclearBaitNode();\n\t}\n\t\n\t/**\n\t* Fire all registered listeners\n\t*/\n\tfunction notifyListeners(){\n\t\tvar i, funcs;\n\t\tif(findResult === null){\n\t\t\treturn;\n\t\t}\n\t\tfor(i=0;i<listeners.length;i++){\n\t\t\tfuncs = listeners[i];\n\t\t\ttry{\t\t\t\n\t\t\t\tif(funcs != null){\n\t\t\t\t\tif(isFunc(funcs['complete'])){\n\t\t\t\t\t\tfuncs['complete'](findResult);\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tif(findResult && isFunc(funcs['found'])){\n\t\t\t\t\t\tfuncs['found']();\n\t\t\t\t\t}\n\t\t\t\t\telse if(findResult === false && isFunc(funcs['notfound'])){\n\t\t\t\t\t\tfuncs['notfound']();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch(ex){\n\t\t\t\tlog('Failure in notify listeners ' + ex.Message, true);\n\t\t\t}\n\t\t}\n\t}\n\t\n\t/**\n\t* Attaches event listener or fires if events have already passed.\n\t*/\n\tfunction attachOrFire(){\n\t\tvar fireNow = false;\n\t\tvar fn;\n\t\t\n\t\tif(document.readyState){\n\t\t\tif(document.readyState == 'complete'){\n\t\t\t\tfireNow = true;\n\t\t\t}\n\t\t}\n\t\t\n\t\tfn = function(){\n\t\t\tbeginTest(quickBait, false);\n\t\t}\n\t\t\n\t\tif(fireNow){\n\t\t\tfn();\n\t\t}\n\t\telse{\n\t\t\tattachEventListener(win, 'load', fn);\n\t\t}\n\t}\n\t\n\t\n\tvar blockLists; // tracks external block lists\n\t\n\t/**\n\t* Public interface of adblock detector\n\t*/\n\tvar impl = {\n\t\t/**\n\t\t* Version of the adblock detector package\n\t\t*/\n\t\tversion: version,\n\t\t\n\t\t/**\n\t\t* Initialization function. See comments at top for options object\n\t\t*/\n\t\tinit: function(options){\n\t\t\tvar k, v, funcs;\n\t\t\t\n\t\t\tif(!options){\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tfuncs = {\n\t\t\t\tcomplete: noop,\n\t\t\t\tfound: noop,\n\t\t\t\tnotfound: noop\n\t\t\t};\n\t\t\t\n\t\t\tfor(k in options){\n\t\t\t\tif(options.hasOwnProperty(k)){\n\t\t\t\t\tif(k == 'complete' || k == 'found' || k == 'notFound'){\n\t\t\t\t\t\tfuncs[k.toLowerCase()] = options[k];\n\t\t\t\t\t}\n\t\t\t\t\telse{\n\t\t\t\t\t\t_options[k] = options[k];\n\t\t\t\t\t}\t\t\t\t\t\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tlisteners.push(funcs);\n\t\t\t\n\t\t\tblockLists = new BlockListTracker();\n\t\t\t\n\t\t\tattachOrFire();\n\t\t}\n\t}\n\t\n\twin['adblockDetector'] = impl;\n\n})(window)\t\n"
  },
  {
    "path": "adblockDetectorWithGA.js",
    "content": "// ===============================================\n// AdBlock detector\n//\n// Attempts to detect the presence of Ad Blocker software and notify listener of its existence.\n// Copyright (c) 2017 IAB\n//\n// The BSD-3 License\n// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:\n// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.\n// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.\n// 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.\n// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n// ===============================================\n\n/**\n* @name window.adblockDetector\n*\n* IAB Adblock detector.\n* Usage: window.adblockDetector.init(options);\n*\n* Options object settings\n*\n*   @prop blockLists: \tArray\n*         Array of string URLs to additional external definition files for bait\n*\n*\t@prop testRemoteList: boolean\n*         Flag to indicate a remote list should be used for testing\n*         in addition to the simple bait definition in this file.\n*         true:  Download external bait definition\n*         false: Only test with quick bait\n*\n*\t@prop debug:  boolean\n*         Flag to indicate additional debug output should be printed to console\n*\n*\t@prop debug:  useLocalBait\n*         Flag to turn on or off usage of the internal quick bait.\n*         This is primarily used for testing of remote bait. True by default\n*\n*\t@prop found: @function\n*         Callback function to fire if adblock is detected\n*\n*\t@prop notfound: @function\n*         Callback function to fire if adblock is not detected.\n*         NOTE: this function may fire multiple times and give false negative\n*         responses during a test until adblock is successfully detected.\n*\n*\t@prop complete: @function\n*         Callback function to fire once a round of testing is complete.\n*         The test result (boolean) is included as a parameter to callback\n*\n* example: \twindow.adblockDetector.init(\n\t\t\t\t{\n\t\t\t\t\tblockLists: ['example_remote_adblockdetector_data.js'],\n\t\t\t\t\tfound: function(){ ...},\n \t\t\t\t\tnotFound: function(){...}\n\t\t\t\t}\n\t\t\t);\n*\n*\n*/\n\n\"use strict\";\n(function(win) {\n\n\tvar ENABLE_ANALYTICS = true;\n\tvar GA_TRACKING_ID = ''; // sample for http://adblockdetector.emination.com/\n\tvar analytics = {}; // later initialized\n\n\t// Credit to Easylist https://easylist.adblockplus.org/en/\n\t// var blockListUrl = 'https://easylist-downloads.adblockplus.org/easylist_noadult.txt'\n\n\tvar ofs = 'offset', cl = 'client';\n\tvar noop = function(){};\n\n\tvar testedOnce = false;\n\tvar testExecuting = false;\n\n\tvar isOldIEevents = (win.addEventListener === undefined);\n\n\t/**\n\t* Options set with default options initialized\n\t*\n\t*/\n\tvar _options = {\n\t\tloopDelay: 50,\n\t\tmaxLoop: 5,\n\t\ttestRemoteList: true,\n\t\tdebug: true,\n\t\tuseLocalBait: true,\n\t\tblockLists: [],\n\t\tfound: noop, \t\t\t\t\t// function to fire when adblock detected\n\t\tnotfound: noop, \t\t\t\t// function to fire if adblock not detected after testing\n\t\tcomplete: noop  \t\t\t\t// function to fire after testing completes, passing result as parameter\n\t}\n\n\tfunction parseAsJson(data){\n\t\tvar result, fnData;\n\t\ttry{\n\t\t\tresult = JSON.parse(data);\n\t\t}\n\t\tcatch(ex){\n\t\t\ttry{\n\t\t\t\tfnData = new Function(\"return \" + data);\n\t\t\t\tresult = fnData();\n\t\t\t}\n\t\t\tcatch(ex){\n\t\t\t\tlog('Failed secondary JSON parse', true);\n\t\t\t}\n\t\t}\n\n\t\treturn result;\n\t}\n\n\t/**\n\t* Ajax helper object to download external scripts.\n\t* Initialize object with an options object\n\t* Ex:\n\t  {\n\t\t  url : 'http://example.org/url_to_download',\n\t\t  method: 'POST|GET',\n\t\t  success: callback_function,\n\t\t  fail:  callback_function\n\t  }\n\t*/\n\tvar AjaxHelper = function(opts){\n\t\tvar xhr = new XMLHttpRequest();\n\n\t\tthis.success = opts.success || noop;\n\t\tthis.fail = opts.fail || noop;\n\t\tvar me = this;\n\n\t\tvar method = opts.method || 'get';\n\n\t\t/**\n\t\t* Abort the request\n\t\t*/\n\t\tthis.abort = function(){\n\t\t\ttry{\n\t\t\t\txhr.abort();\n\t\t\t}\n\t\t\tcatch(ex){\n\t\t\t}\n\t\t}\n\n\t\tfunction stateChange(vals){\n\t\t\tif(xhr.readyState == 4){\n\t\t\t\tif(xhr.status == 200){\n\t\t\t\t\tme.success(xhr.response);\n\t\t\t\t}\n\t\t\t\telse{\n\t\t\t\t\t// failed\n\t\t\t\t\tme.fail(xhr.status);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\txhr.onreadystatechange = stateChange;\n\n\t\tfunction start(){\n\t\t\txhr.open(method, opts.url, true);\n\t\t\txhr.send();\n\t\t}\n\n\t\tstart();\n\t}\n\n\t/**\n\t* Object tracking the various block lists\n\t*/\n\tvar BlockListTracker = function(){\n\t\tvar me = this;\n\t\tvar externalBlocklistData = {};\n\n\t\t/**\n\t\t* Add a new external URL to track\n\t\t*/\n\t\tthis.addUrl = function(url){\n\t\t\texternalBlocklistData[url] = {\n\t\t\t\turl: url,\n\t\t\t\tstate: 'pending',\n\t\t\t\tformat: null,\n\t\t\t\tdata: null,\n\t\t\t\tresult: null\n\t\t\t}\n\n\t\t\treturn externalBlocklistData[url];\n\t\t}\n\n\t\t/**\n\t\t* Loads a block list definition\n\t\t*/\n\t\tthis.setResult = function(urlKey, state, data){\n\t\t\tvar obj = externalBlocklistData[urlKey];\n\t\t\tif(obj == null){\n\t\t\t\tobj = this.addUrl(urlKey);\n\t\t\t}\n\n\t\t\tobj.state = state;\n\t\t\tif(data == null){\n\t\t\t\tobj.result = null;\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif(typeof data === 'string'){\n\t\t\t\ttry{\n\t\t\t\t\tdata = parseAsJson(data);\n\t\t\t\t\tobj.format = 'json';\n\t\t\t\t}\n\t\t\t\tcatch(ex){\n\t\t\t\t\tobj.format = 'easylist';\n\t\t\t\t\t// parseEasyList(data);\n\t\t\t\t}\n\t\t\t}\n\t\t\tobj.data = data;\n\n\t\t\treturn obj;\n\t\t}\n\n\t}\n\n\tvar listeners = []; // event response listeners\n\tvar baitNode = null;\n\tvar quickBait = {\n\t\tcssClass: 'pub_300x250 pub_300x250m pub_728x90 text-ad textAd text_ad text_ads text-ads text-ad-links'\n\t};\n\tvar baitTriggers = {\n\t\tnullProps: [ofs + 'Parent'],\n\t\tzeroProps: []\n\t};\n\n\tbaitTriggers.zeroProps = [\n\t\tofs +'Height', ofs +'Left', ofs +'Top', ofs +'Width', ofs +'Height',\n\t\tcl + 'Height', cl + 'Width'\n\t];\n\n\t// result object\n\tvar exeResult = {\n\t\tquick: null,\n\t\tremote: null\n\t};\n\n\tvar findResult = null; // result of test for ad blocker\n\n\tvar timerIds = {\n\t\ttest: 0,\n\t\tdownload: 0\n\t};\n\n\tfunction isFunc(fn){\n\t\treturn typeof(fn) == 'function';\n\t}\n\n\t/**\n\t* Make a DOM element\n\t*/\n\tfunction makeEl(tag, attributes){\n\t\tvar k, v, el, attr = attributes;\n\t\tvar d = document;\n\n\t\tel = d.createElement(tag);\n\n\t\tif(attr){\n\t\t\tfor(k in attr){\n\t\t\t\tif(attr.hasOwnProperty(k)){\n\t\t\t\t\tel.setAttribute(k, attr[k]);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn el;\n\t}\n\n\tfunction attachEventListener(dom, eventName, handler){\n\t\tif(isOldIEevents){\n\t\t\tdom.attachEvent('on' + eventName, handler);\n\t\t}\n\t\telse{\n\t\t\tdom.addEventListener(eventName, handler, false);\n\t\t}\n\t}\n\n\tfunction log(message, isError){\n\t\tif(!_options.debug && !isError){\n\t\t\treturn;\n\t\t}\n\t\tif(win.console && win.console.log){\n\t\t\tif(isError){\n\t\t\t\tconsole.error('[ABD] ' + message);\n\t\t\t}\n\t\t\telse{\n\t\t\t\tconsole.log('[ABD] ' + message);\n\t\t\t}\n\t\t}\n\t}\n\n\tvar ajaxDownloads = [];\n\n\t/**\n\t* Load and execute the URL inside a closure function\n\t*/\n\tfunction loadExecuteUrl(url){\n\t\tvar ajax, result;\n\t\tblockLists.addUrl(url);\n\t\t// setup call for remote list\n\t\tajax = new AjaxHelper(\n\t\t\t{\n\t\t\t\turl: url,\n\t\t\t\tsuccess: function(data){\n\t\t\t\t\tlog('downloaded file ' + url); // todo - parse and store until use\n\t\t\t\t\tresult = blockLists.setResult(url, 'success', data);\n\t\t\t\t\ttry{\n\t\t\t\t\t\tvar intervalId = 0,\n\t\t\t\t\t\t\tretryCount = 0;\n\n\t\t\t\t\t\tvar tryExecuteTest = function(listData){\n\t\t\t\t\t\t\tif(!testExecuting){\n\t\t\t\t\t\t\t\tbeginTest(listData, true);\n\t\t\t\t\t\t\t\treturn true;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif(findResult == true){\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif(tryExecuteTest(result.data)){\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse{\n\t\t\t\t\t\t\tlog('Pause before test execution');\n\t\t\t\t\t\t\tintervalId = setInterval(function(){\n\t\t\t\t\t\t\t\tif(tryExecuteTest(result.data) || retryCount++ > 5){\n\t\t\t\t\t\t\t\t\tclearInterval(intervalId);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}, 250);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tcatch(ex){\n\t\t\t\t\t\tlog(ex.message + ' url: ' + url, true);\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\tfail: function(status){\n\t\t\t\t\tlog(status, true);\n\t\t\t\t\tblockLists.setResult(url, 'error', null);\n\t\t\t\t}\n\t\t\t});\n\n\t\tajaxDownloads.push(ajax);\n\t}\n\n\n\t/**\n\t* Fetch the external lists and initiate the tests\n\t*/\n\tfunction fetchRemoteLists(){\n\t\tvar i, url;\n\t\tvar opts = _options;\n\n\t\tfor(i=0;i<opts.blockLists.length;i++){\n\t\t\turl = opts.blockLists[i];\n\t\t\tloadExecuteUrl(url);\n\t\t}\n\t}\n\n\tfunction cancelRemoteDownloads(){\n\t\tvar i, aj;\n\n\t\tfor(i=ajaxDownloads.length-1;i >= 0;i--){\n\t\t\taj = ajaxDownloads.pop();\n\t\t\taj.abort();\n\t\t}\n\t}\n\n\n\t// =============================================================================\n\t/**\n\t* Begin execution of the test\n\t*/\n\tfunction beginTest(bait, isRemote){\n\n\t\tif(findResult == true){\n\t\t\treturn; // we found it. don't continue executing\n\t\t}\n\t\ttestExecuting = true;\n\t\tcastBait(bait);\n\n\t\tif(!isRemote){\n\t\t\texeResult.quick = 'testing';\n\t\t}\n\t\telse {\n\t\t\texeResult.remote = 'testing';\n\t\t}\n\n\t\ttimerIds.test = setTimeout(\n\t\t\tfunction(){ reelIn(bait, 1); },\n\t\t\t5);\n\n\t\tif(!isRemote && _options.testRemoteList){\n\t\t\tfetchRemoteLists();\n\t\t}\n\t}\n\n\t/**\n\t* Create the bait node to see how the browser page reacts\n\t*/\n\tfunction castBait(bait){\n\n\t\tvar i, d = document, b = d.body;\n\t\tvar t;\n\t\tvar baitStyle = 'width: 1px !important; height: 1px !important; position: absolute !important; left: -10000px !important; top: -1000px !important;'\n\n\t\tif(bait == null || typeof(bait) == 'string'){\n\t\t\tlog('invalid bait being cast');\n\t\t\treturn;\n\t\t}\n\n\t\tif(bait.style != null){\n\t\t\tbaitStyle += bait.style;\n\t\t}\n\n\t\tbaitNode = makeEl('div', {\n\t\t\t'class': bait.cssClass,\n\t\t\t'style': baitStyle\n\t\t});\n\n\t\tlog('adding bait node to DOM');\n\t\tb.appendChild(baitNode);\n\n\t\t// touch these properties to insure initialization\n\t\tfor(i=0;i<baitTriggers.nullProps.length;i++){\n\t\t\tt = baitNode[baitTriggers.nullProps[i]];\n\t\t}\n\t\tfor(i=0;i<baitTriggers.zeroProps.length;i++){\n\t\t\tt = baitNode[baitTriggers.zeroProps[i]];\n\t\t}\n\t}\n\n\t/**\n\t* Run tests to see if browser has taken the bait and blocked the bait element\n\t*/\n\tfunction reelIn(bait, attemptNum){\n\t\tvar i, k, v;\n\t\tvar body = document.body;\n\t\tvar found = false;\n\t\tvar findTrigger = null;\n\n\t\tif(baitNode == null){\n\t\t\tlog('recast bait');\n\t\t\tcastBait(bait || quickBait);\n\t\t}\n\n\t\tif(typeof(bait) == 'string'){\n\t\t\tlog('invalid bait used', true);\n\t\t\tif(clearBaitNode()){\n\t\t\t\tsetTimeout(function(){\n\t\t\t\t\ttestExecuting = false;\n\t\t\t\t}, 5);\n\t\t\t}\n\n\t\t\treturn;\n\t\t}\n\n\t\tif(timerIds.test > 0){\n\t\t\tclearTimeout(timerIds.test);\n\t\t\ttimerIds.test = 0;\n\t\t}\n\n\t\t// test for issues\n\n\t\tif(body.getAttribute('abp') !== null){\n\t\t\tlog('found adblock body attribute');\n\t\t\tfound = true;\n\t\t\tfindTrigger = 'body_abp_attr';\n\t\t}\n\n\t\tif(!found){\n\t\t\tfor(i=0;i<baitTriggers.nullProps.length;i++){\n\t\t\t\tif(baitNode[baitTriggers.nullProps[i]] == null){\n\t\t\t\t\tif(attemptNum>4)\n\t\t\t\t\t\tfound = true;\n\t\t\t\t\tlog('found adblock null attr: ' + baitTriggers.nullProps[i]);\n\t\t\t\t\tfindTrigger = 'div hidden with attribute: null attr-' + baitTriggers.nullProps[i];\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tif(found == true){\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfor(i=0;i<baitTriggers.zeroProps.length;i++){\n\t\t\t\tif(found == true){\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tif(baitNode[baitTriggers.zeroProps[i]] == 0){\n\t\t\t\t\tif(attemptNum>4){\n\t\t\t\t\t\t\tfound = true;\n\t\t\t\t\t}\n\t\t\t\t\tfindTrigger = 'div hidden with attribute: zero_attr-' + baitTriggers.zeroProps[i];\n\t\t\t\t\tlog('found adblock zero attr: ' + baitTriggers.zeroProps[i]);\n\t\t\t\t}\n\t\t\t\tif(baitNode[baitTriggers.zeroProps[i]] == 1){\n\t\t\t\t\tfindTrigger = 'div visible with attribute: zero_attr-' + baitTriggers.zeroProps[i];\n\t\t\t\t\tlog('found adblock zero attr: ' + baitTriggers.zeroProps[i]);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif(!found){\n\t\t\tif(window.getComputedStyle !== undefined) {\n\t\t\t\tvar baitTemp = window.getComputedStyle(baitNode, null);\n\t\t\t\tif(baitTemp.getPropertyValue('display') == 'none'\n\t\t\t\t|| baitTemp.getPropertyValue('visibility') == 'hidden') {\n\t\t\t\t\tif(attemptNum>4)\n\t\t\t\t\tfound = true;\n\t\t\t\t\tfindTrigger = 'computedStyle indicator';\n\t\t\t\t\tlog('found adblock computedStyle indicator');\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\ttestedOnce = true;\n\t\tif(found || attemptNum++ >= _options.maxLoop){\n\t\t\tfindResult = found;\n\t\t\ttry{\n\t\t\t\tif(found){\n\t\t\t\t\tanalytics.blockerDetected(findTrigger, attemptNum);\n\t\t\t\t}\n\t\t\t\telse{\n\t\t\t\t\tanalytics.blockerNotDetected(findTrigger, attemptNum);\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch(ex){\n\t\t\t\tlog(ex.message);\n\t\t\t}\n\n\t\t\tlog('exiting test loop - value: ' + findResult);\n\t\t\tnotifyListeners();\n\t\t\tif(clearBaitNode()){\n\t\t\t\tsetTimeout(function(){\n\t\t\t\t\ttestExecuting = false;\n\t\t\t\t}, 5);\n\t\t\t}\n\t\t}\n\t\telse{\n\t\t\ttimerIds.test = setTimeout(function(){\n\t\t\t\treelIn(bait, attemptNum);\n\t\t\t}, _options.loopDelay);\n\t\t}\n\t}\n\n\tfunction clearBaitNode(){\n\t\tif(baitNode === null){\n\t\t\treturn true;\n\t\t}\n\n\t\ttry{\n\t\t\tif(isFunc(baitNode.remove)){\n\t\t\t\tbaitNode.remove();\n\t\t\t}\n\t\t\tdocument.body.removeChild(baitNode);\n\t\t}\n\t\tcatch(ex){\n\t\t}\n\t\tbaitNode = null;\n\n\t\treturn true;\n\t}\n\n\t/**\n\t* Halt the test and any pending timeouts\n\t*/\n\tfunction stopFishing(){\n\t\tif(timerIds.test > 0){\n\t\t\tclearTimeout(timerIds.test);\n\t\t}\n\t\tif(timerIds.download > 0){\n\t\t\tclearTimeout(timerIds.download);\n\t\t}\n\n\t\tcancelRemoteDownloads();\n\n\t\tclearBaitNode();\n\t}\n\n\t/**\n\t* Fire all registered listeners\n\t*/\n\tfunction notifyListeners(){\n\n\t\tvar i, funcs;\n\t\tif(findResult === null){\n\t\t\treturn;\n\t\t}\n\t\tfor(i=0;i<listeners.length;i++){\n\t\t\tfuncs = listeners[i];\n\t\t\ttry{\n\t\t\t\tif(funcs != null){\n\t\t\t\t\tif(isFunc(funcs['complete'])){\n\t\t\t\t\t\tfuncs['complete'](findResult);\n\t\t\t\t\t}\n\n\t\t\t\t\tif(findResult && isFunc(funcs['found'])){\n\t\t\t\t\t\tfuncs['found']();\n\t\t\t\t\t}\n\t\t\t\t\telse if(findResult === false && isFunc(funcs['notfound'])){\n\t\t\t\t\t\tfuncs['notfound']();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch(ex){\n\t\t\t\tlog('Failure in notify listeners ' + ex.Message, true);\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t* Attaches event listener or fires if events have already passed.\n\t*/\n\tfunction attachOrFire(){\n\n\t\tvar fireNow = false;\n\t\tvar fn;\n\n\t\tif(document.readyState){\n\t\t\tif(document.readyState == 'complete'){\n\t\t\t\tfireNow = true;\n\t\t\t}\n\t\t}\n\n\t\tfn = function(){\n\t\t\tif(_options.useLocalBait){\n\t\t\t\tbeginTest(quickBait, false);\n\t\t\t}\n\t\t\telse{\n\t\t\t\tlog('ignoreing local bait - download remote');\n\t\t\t\tfetchRemoteLists();\n\t\t\t}\n\t\t}\n\n\t\tif(fireNow){\n\t\t\tfn();\n\t\t}\n\t\telse{\n\t\t\tattachEventListener(win, 'load', fn);\n\t\t}\n\t}\n\n\n\tvar blockLists; // tracks external block lists\n\n\tvar impl = {\n\n\t\tinit: function(options){\n\t\t\tvar k, v, funcs;\n\n\t\t\tif(!options){\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tfuncs = {\n\t\t\t\tcomplete: noop,\n\t\t\t\tfound: noop,\n\t\t\t\tnotfound: noop\n\t\t\t};\n\n\t\t\tfor(k in options){\n\t\t\t\tif(options.hasOwnProperty(k)){\n\t\t\t\t\tif(k == 'complete' || k == 'found' || k == 'notFound'){\n\t\t\t\t\t\tfuncs[k.toLowerCase()] = options[k];\n\t\t\t\t\t}\n\t\t\t\t\telse{\n\t\t\t\t\t\t_options[k] = options[k];\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tlisteners.push(funcs);\n\n\t\t\tblockLists = new BlockListTracker();\n\n\t\t\tattachOrFire();\n\t\t}\n\t}\n\n\twin['adblockDetector'] = impl;\n\n\n\t// ================= ANALYTICS WRAPPER ==================\n\t/**\n\t* Object literal wrapper for the various analytics frameworks\n\t*/\n\tanalytics = {\n\t\tkey: {\n\t\t\tBLOCKER : 'AdBlocker',\n\t\t\tFOUND : 'Found',\n\t\t\tNOT_FOUND: 'NotFound',\n\t\t\tDETECT: 'Detect'\n\t\t},\n\n\t\trecordEvent: function(category, action, label, value){\n\t\t\tif(!ENABLE_ANALYTICS){\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// send, event, CATEGORY, ACTION, LABEL, VALUE\n\t\t\tga('send', 'event', category, action, label, value);\n\n\t\t},\n\n\t\tblockerDetected: function(triggerFound, attemptNum){\n\t\t\tvar k = analytics.key;\n\t\t\tanalytics.recordEvent(k.DETECT, k.FOUND, triggerFound, attemptNum);\n\t\t},\n\n\t\tblockerNotDetected: function(triggerFound, attemptNum){\n\t\t\tvar k = analytics.key;\n\t\t\tanalytics.recordEvent(k.DETECT, k.NOT_FOUND, triggerFound, attemptNum);\n\t\t}\n\n\t}\n\n\n\t// Addition of Analytics\n\tfunction initAnalytics(ga_code){\n\n\t  (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){\n\t  (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),\n\t  m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)\n\t  })(window,document,'script','//www.google-analytics.com/analytics.js','ga');\n\n\t  ga('create', ga_code, 'auto');\n\t  //ga('send', 'pageview');\n\t}\n\n\n\t// init analytics inline\n\tif(ENABLE_ANALYTICS){\n\t\tinitAnalytics(GA_TRACKING_ID);\n\t}\n\n})(window)\n"
  },
  {
    "path": "test.html",
    "content": "<!doctype html>\n<html>\n<head>\n\t<title>AdBlock</title>\n\t<meta charset=\"utf-8\">\n\t<meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n\t<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n\t<link href=\"http://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css\" rel=\"stylesheet\">\n\t<link href=\"http://cdnjs.cloudflare.com/ajax/libs/highlight.js/8.7/styles/default.min.css\" rel=\"stylesheet\">\n<style>\n\th5.bg-success,h5.bg-danger {\n\t\tpadding: 8px;\n\t\tborder: 1px solid #cccccc;\n\t\tborder-radius: 4px;\n\t\ttext-align: center;\n\t}\n\t.center {\n\t   width: 300px;\n\t   height: 300px;\n\t   position: absolute;\n\t   left: 50%;\n\t   top: 50%; \n\t   margin-left: -150px;\n\t   margin-top: -150px;\n\t}\n\t.below {\n\t   width: 300px;\n\t   height: 300px;\n\t   position: absolute;\n\t   left: 60%;\n\t   top: 60%; \n\t   margin-left: -150px;\n\t   margin-top: -150px;\n\t}\n</style>\n</head>\n<body>\n\t\t<div class=\"center\">\n\t\t\t\t<h5 class=\"bg-success\" id=\"adb-not-enabled\" style=\"display: none;\">AdBlock is disabled</h5>\n\t\t\t\t<h5 class=\"bg-danger\" id=\"adb-enabled\" style=\"display: none;\">AdBlock is enabled</h5>\n\t\t</div>\n\t\t<div class=\"below\">\n\t\t\t<input TYPE=\"button\" onClick=\"history.go(0)\" VALUE=\"Reload Page\">\n\t\t</div>\n\n\t<script src=\"./adblockDetector.js\"></script>\n\t<script>\n\t// Configure the adblock detector\n\t(function(){\n\t\tvar enabledEl = document.getElementById('adb-enabled');\n\t\tvar disabledEl = document.getElementById('adb-not-enabled');\n\t\tfunction adBlockDetected() {\n\t\t\tenabledEl.style.display = 'block';\n\t\t\tdisabledEl.style.display = 'none';\n\t\t}\n\t\tfunction adBlockNotDetected() {\n\t\t\tdisabledEl.style.display = 'block';\n\t\t\tenabledEl.style.display = 'none';\n\t\t}\n\t\t\n\t\tif(typeof window.adblockDetector === 'undefined') {\n\t\t\tadBlockDetected();\n\t\t} else {\n\t\t\twindow.adblockDetector.init(\n\t\t\t\t{\n\t\t\t\t\tdebug: true,\n\t\t\t\t\tfound: function(){\n\t\t\t\t\t\tadBlockDetected();\n\t\t\t\t\t},\n\t\t\t\t\tnotFound: function(){\n\t\t\t\t\t\tadBlockNotDetected();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t);\n\t\t}\n\t}());\n\t</script>\n\t\t\n</body>\n</html>"
  }
]