{
  "instrumentation": "node-jscoverage",
  "sloc": 903,
  "hits": 354,
  "misses": 549,
  "coverage": 39.202657807308974,
  "files": [
    {
      "filename": "src/feedhenry.js",
      "coverage": 76.81159420289855,
      "hits": 53,
      "misses": 16,
      "sloc": 69,
      "source": {
        "1": {
          "source": "var constants = require(\"./modules/constants\");",
          "coverage": 1
        },
        "2": {
          "source": "var events = require(\"./modules/events\");",
          "coverage": 1
        },
        "3": {
          "source": "var logger = require(\"./modules/logger\");",
          "coverage": 1
        },
        "4": {
          "source": "var ajax = require(\"./modules/ajax\");",
          "coverage": 1
        },
        "5": {
          "source": "var events = require(\"./modules/events\");",
          "coverage": 1
        },
        "6": {
          "source": "var cloud = require(\"./modules/waitForCloud\");",
          "coverage": 1
        },
        "7": {
          "source": "var api_act = require(\"./modules/api_act\");",
          "coverage": 1
        },
        "8": {
          "source": "var api_auth = require(\"./modules/api_auth\");",
          "coverage": 1
        },
        "9": {
          "source": "var api_sec = require(\"./modules/api_sec\");",
          "coverage": 1
        },
        "10": {
          "source": "var api_hash = require(\"./modules/api_hash\");",
          "coverage": 1
        },
        "11": {
          "source": "var api_mbaas = require(\"./modules/api_mbaas\");",
          "coverage": 1
        },
        "12": {
          "source": "var api_cloud = require(\"./modules/api_cloud\");",
          "coverage": 1
        },
        "13": {
          "source": "var api_push = require(\"./modules/api_push\");",
          "coverage": 1
        },
        "14": {
          "source": "var fhparams = require(\"./modules/fhparams\");",
          "coverage": 1
        },
        "15": {
          "source": "var appProps = require(\"./modules/appProps\");",
          "coverage": 1
        },
        "16": {
          "source": "var device = require(\"./modules/device\");",
          "coverage": 1
        },
        "17": {
          "source": "var syncCloudHandler = require(\"./modules/sync_cloud_handler\");",
          "coverage": 1
        },
        "18": {
          "source": "",
          "coverage": ""
        },
        "19": {
          "source": "var defaultFail = function(msg, error) {",
          "coverage": 1
        },
        "20": {
          "source": "  logger.error(msg + \":\" + JSON.stringify(error));",
          "coverage": 0
        },
        "21": {
          "source": "};",
          "coverage": ""
        },
        "22": {
          "source": "",
          "coverage": ""
        },
        "23": {
          "source": "var addListener = function(type, listener) {",
          "coverage": 1
        },
        "24": {
          "source": "  events.addListener(type, listener);",
          "coverage": 2
        },
        "25": {
          "source": "  if (type === constants.INIT_EVENT) {",
          "coverage": ""
        },
        "26": {
          "source": "    //for fhinit event, need to check the status of cloud and may need to fire the listener immediately.",
          "coverage": ""
        },
        "27": {
          "source": "    if (cloud.isReady()) {",
          "coverage": ""
        },
        "28": {
          "source": "      listener(null, {",
          "coverage": 0
        },
        "29": {
          "source": "        host: cloud.getCloudHostUrl()",
          "coverage": ""
        },
        "30": {
          "source": "      });",
          "coverage": ""
        },
        "31": {
          "source": "    } else if (cloud.getInitError()) {",
          "coverage": ""
        },
        "32": {
          "source": "      listener(cloud.getInitError());",
          "coverage": 0
        },
        "33": {
          "source": "    }",
          "coverage": ""
        },
        "34": {
          "source": "  }",
          "coverage": ""
        },
        "35": {
          "source": "};",
          "coverage": ""
        },
        "36": {
          "source": "",
          "coverage": ""
        },
        "37": {
          "source": "var once = function(type, listener) {",
          "coverage": 1
        },
        "38": {
          "source": "  if (type === constants.INIT_EVENT && cloud.isReady()) {",
          "coverage": ""
        },
        "39": {
          "source": "    listener(null, {",
          "coverage": 0
        },
        "40": {
          "source": "      host: cloud.getCloudHostUrl()",
          "coverage": ""
        },
        "41": {
          "source": "    });",
          "coverage": ""
        },
        "42": {
          "source": "  } else if (type === constants.INIT_EVENT && cloud.getInitError()) {",
          "coverage": ""
        },
        "43": {
          "source": "    listener(cloud.getInitError());",
          "coverage": 0
        },
        "44": {
          "source": "  } else {",
          "coverage": ""
        },
        "45": {
          "source": "    events.once(type, listener);",
          "coverage": 0
        },
        "46": {
          "source": "  }",
          "coverage": ""
        },
        "47": {
          "source": "};",
          "coverage": ""
        },
        "48": {
          "source": "",
          "coverage": ""
        },
        "49": {
          "source": "//Legacy shim. Init hapens based on fhconfig.json or, for v2, global var called fh_app_props which is injected as part of the index.html wrapper",
          "coverage": ""
        },
        "50": {
          "source": "var init = function(opts, success, fail) {",
          "coverage": 1
        },
        "51": {
          "source": "  logger.warn(\"$fh.init will be deprecated soon\");",
          "coverage": 0
        },
        "52": {
          "source": "  cloud.ready(function(err, host) {",
          "coverage": 0
        },
        "53": {
          "source": "    if (err) {",
          "coverage": ""
        },
        "54": {
          "source": "      if (typeof fail === \"function\") {",
          "coverage": ""
        },
        "55": {
          "source": "        return fail(err);",
          "coverage": 0
        },
        "56": {
          "source": "      }",
          "coverage": ""
        },
        "57": {
          "source": "    } else {",
          "coverage": ""
        },
        "58": {
          "source": "      if (typeof success === \"function\") {",
          "coverage": ""
        },
        "59": {
          "source": "        success(host.host);",
          "coverage": 0
        },
        "60": {
          "source": "      }",
          "coverage": ""
        },
        "61": {
          "source": "    }",
          "coverage": ""
        },
        "62": {
          "source": "  });",
          "coverage": ""
        },
        "63": {
          "source": "};",
          "coverage": ""
        },
        "64": {
          "source": "",
          "coverage": ""
        },
        "65": {
          "source": "var fh = window.$fh || {};",
          "coverage": 1
        },
        "66": {
          "source": "fh.init = init;",
          "coverage": 1
        },
        "67": {
          "source": "fh.act = api_act;",
          "coverage": 1
        },
        "68": {
          "source": "fh.auth = api_auth;",
          "coverage": 1
        },
        "69": {
          "source": "fh.cloud = api_cloud;",
          "coverage": 1
        },
        "70": {
          "source": "fh.sec = api_sec;",
          "coverage": 1
        },
        "71": {
          "source": "fh.hash = api_hash;",
          "coverage": 1
        },
        "72": {
          "source": "fh.push = api_push;",
          "coverage": 1
        },
        "73": {
          "source": "fh.ajax = fh.__ajax = ajax;",
          "coverage": 1
        },
        "74": {
          "source": "fh.mbaas = api_mbaas;",
          "coverage": 1
        },
        "75": {
          "source": "",
          "coverage": ""
        },
        "76": {
          "source": "// Mount sync to fh namespace",
          "coverage": ""
        },
        "77": {
          "source": "fh.sync = require(\"fh-sync-js\");",
          "coverage": 1
        },
        "78": {
          "source": "fh.sync.setCloudHandler(syncCloudHandler);",
          "coverage": 1
        },
        "79": {
          "source": "",
          "coverage": ""
        },
        "80": {
          "source": "fh._getDeviceId = device.getDeviceId;",
          "coverage": 1
        },
        "81": {
          "source": "fh.fh_timeout = 60000; //keep backward compatible",
          "coverage": 1
        },
        "82": {
          "source": "",
          "coverage": ""
        },
        "83": {
          "source": "fh.getCloudURL = function() {",
          "coverage": 1
        },
        "84": {
          "source": "  return cloud.getCloudHostUrl();",
          "coverage": 0
        },
        "85": {
          "source": "};",
          "coverage": ""
        },
        "86": {
          "source": "",
          "coverage": ""
        },
        "87": {
          "source": "fh.getFHParams = function() {",
          "coverage": 1
        },
        "88": {
          "source": "  return fhparams.buildFHParams();",
          "coverage": 0
        },
        "89": {
          "source": "};",
          "coverage": ""
        },
        "90": {
          "source": "",
          "coverage": ""
        },
        "91": {
          "source": "fh.getFHHeaders = function() {",
          "coverage": 1
        },
        "92": {
          "source": "  return fhparams.getFHHeaders();",
          "coverage": 0
        },
        "93": {
          "source": "};",
          "coverage": ""
        },
        "94": {
          "source": "",
          "coverage": ""
        },
        "95": {
          "source": "//events",
          "coverage": ""
        },
        "96": {
          "source": "fh.addListener = addListener;",
          "coverage": 1
        },
        "97": {
          "source": "fh.on = addListener;",
          "coverage": 1
        },
        "98": {
          "source": "fh.once = once;",
          "coverage": 1
        },
        "99": {
          "source": "var methods = [\"removeListener\", \"removeAllListeners\", \"setMaxListeners\", \"listeners\", \"emit\"];",
          "coverage": 1
        },
        "100": {
          "source": "for (var i = 0; i < methods.length; i++) {",
          "coverage": ""
        },
        "101": {
          "source": "  fh[methods[i]] = events[methods[i]];",
          "coverage": 5
        },
        "102": {
          "source": "}",
          "coverage": ""
        },
        "103": {
          "source": "",
          "coverage": ""
        },
        "104": {
          "source": "//keep backward compatibility",
          "coverage": ""
        },
        "105": {
          "source": "fh.on(constants.INIT_EVENT, function(err, host) {",
          "coverage": 1
        },
        "106": {
          "source": "  if (err) {",
          "coverage": ""
        },
        "107": {
          "source": "    fh.cloud_props = {};",
          "coverage": 0
        },
        "108": {
          "source": "    fh.app_props = {};",
          "coverage": 0
        },
        "109": {
          "source": "  } else {",
          "coverage": ""
        },
        "110": {
          "source": "    fh.cloud_props = {",
          "coverage": 1
        },
        "111": {
          "source": "      hosts: {",
          "coverage": ""
        },
        "112": {
          "source": "        url: host.host",
          "coverage": ""
        },
        "113": {
          "source": "      }",
          "coverage": ""
        },
        "114": {
          "source": "    };",
          "coverage": ""
        },
        "115": {
          "source": "    fh.app_props = appProps.getAppProps();",
          "coverage": 1
        },
        "116": {
          "source": "  }",
          "coverage": ""
        },
        "117": {
          "source": "});",
          "coverage": ""
        },
        "118": {
          "source": "",
          "coverage": ""
        },
        "119": {
          "source": "//keep backward compatibility",
          "coverage": ""
        },
        "120": {
          "source": "fh.on(constants.INTERNAL_CONFIG_LOADED_EVENT, function(err, host) {",
          "coverage": 1
        },
        "121": {
          "source": "  if (err) {",
          "coverage": ""
        },
        "122": {
          "source": "    fh.app_props = {};",
          "coverage": 0
        },
        "123": {
          "source": "  } else {",
          "coverage": ""
        },
        "124": {
          "source": "    fh.app_props = appProps.getAppProps();",
          "coverage": 1
        },
        "125": {
          "source": "  }",
          "coverage": ""
        },
        "126": {
          "source": "",
          "coverage": ""
        },
        "127": {
          "source": "  // Emit config loaded event - appprops set at this point",
          "coverage": ""
        },
        "128": {
          "source": "  // V2 legacy SDK uses this to know when to fire $fh.ready (i.e. appprops is now set)",
          "coverage": ""
        },
        "129": {
          "source": "  events.emit(constants.CONFIG_LOADED_EVENT, null);",
          "coverage": 1
        },
        "130": {
          "source": "});",
          "coverage": ""
        },
        "131": {
          "source": "",
          "coverage": ""
        },
        "132": {
          "source": "//for test",
          "coverage": ""
        },
        "133": {
          "source": "fh.reset = cloud.reset;",
          "coverage": 1
        },
        "134": {
          "source": "//we should really stop polluting global name space. Ideally we should ask browserify to use \"$fh\" when umd-fy the module. However, \"$\" is not allowed as the standard module name.",
          "coverage": ""
        },
        "135": {
          "source": "//So, we assign $fh to the window name space directly here. (otherwise, we have to fork the grunt browserify plugin, then fork browerify and the dependent umd module, really not worthing the effort).",
          "coverage": ""
        },
        "136": {
          "source": "window.$fh = fh;",
          "coverage": 1
        },
        "137": {
          "source": "module.exports = fh;",
          "coverage": 1
        }
      }
    },
    {
      "filename": "src/modules/XDomainRequestWrapper.js",
      "coverage": 19.51219512195122,
      "hits": 8,
      "misses": 33,
      "sloc": 41,
      "source": {
        "1": {
          "source": "var urlparser = require('url');",
          "coverage": 2
        },
        "2": {
          "source": "",
          "coverage": ""
        },
        "3": {
          "source": "var XDomainRequestWrapper = function(xdr){",
          "coverage": 2
        },
        "4": {
          "source": "  this.xdr = xdr;",
          "coverage": 0
        },
        "5": {
          "source": "  this.isWrapper = true;",
          "coverage": 0
        },
        "6": {
          "source": "  this.readyState = 0;",
          "coverage": 0
        },
        "7": {
          "source": "  this.onreadystatechange = null;",
          "coverage": 0
        },
        "8": {
          "source": "  this.status = 0;",
          "coverage": 0
        },
        "9": {
          "source": "  this.statusText = \"\";",
          "coverage": 0
        },
        "10": {
          "source": "  this.responseText = \"\";",
          "coverage": 0
        },
        "11": {
          "source": "  this.headers = {};",
          "coverage": 0
        },
        "12": {
          "source": "  var self = this;",
          "coverage": 0
        },
        "13": {
          "source": "  this.xdr.onload = function(){",
          "coverage": 0
        },
        "14": {
          "source": "      self.readyState = 4;",
          "coverage": 0
        },
        "15": {
          "source": "      self.status = 200;",
          "coverage": 0
        },
        "16": {
          "source": "      self.statusText = \"\";",
          "coverage": 0
        },
        "17": {
          "source": "      self.responseText = self.xdr.responseText;",
          "coverage": 0
        },
        "18": {
          "source": "      if(self.onreadystatechange){",
          "coverage": ""
        },
        "19": {
          "source": "          self.onreadystatechange();",
          "coverage": 0
        },
        "20": {
          "source": "      }",
          "coverage": ""
        },
        "21": {
          "source": "  };",
          "coverage": ""
        },
        "22": {
          "source": "  this.xdr.onerror = function(){",
          "coverage": 0
        },
        "23": {
          "source": "      if(self.onerror){",
          "coverage": ""
        },
        "24": {
          "source": "          self.onerror();",
          "coverage": 0
        },
        "25": {
          "source": "      }",
          "coverage": ""
        },
        "26": {
          "source": "      self.readyState = 4;",
          "coverage": 0
        },
        "27": {
          "source": "      self.status = 0;",
          "coverage": 0
        },
        "28": {
          "source": "      self.statusText = \"\";",
          "coverage": 0
        },
        "29": {
          "source": "      if(self.onreadystatechange){",
          "coverage": ""
        },
        "30": {
          "source": "          self.onreadystatechange();",
          "coverage": 0
        },
        "31": {
          "source": "      }",
          "coverage": ""
        },
        "32": {
          "source": "  };",
          "coverage": ""
        },
        "33": {
          "source": "  this.xdr.ontimeout = function(){",
          "coverage": 0
        },
        "34": {
          "source": "      self.readyState = 4;",
          "coverage": 0
        },
        "35": {
          "source": "      self.status = 408;",
          "coverage": 0
        },
        "36": {
          "source": "      self.statusText = \"timeout\";",
          "coverage": 0
        },
        "37": {
          "source": "      if(self.onreadystatechange){",
          "coverage": ""
        },
        "38": {
          "source": "          self.onreadystatechange();",
          "coverage": 0
        },
        "39": {
          "source": "      }",
          "coverage": ""
        },
        "40": {
          "source": "  };",
          "coverage": ""
        },
        "41": {
          "source": "};",
          "coverage": ""
        },
        "42": {
          "source": "",
          "coverage": ""
        },
        "43": {
          "source": "XDomainRequestWrapper.prototype.open = function(method, url, asyn){",
          "coverage": 2
        },
        "44": {
          "source": "  var parsedUrl = urlparser.parse(url, true);",
          "coverage": 0
        },
        "45": {
          "source": "  parsedUrl.query = parsedUrl.query || {};",
          "coverage": 0
        },
        "46": {
          "source": "  parsedUrl.query.fh_headers = this.headers;",
          "coverage": 0
        },
        "47": {
          "source": "  this.xdr.open(method, urlparser.format(parsedUrl));",
          "coverage": 0
        },
        "48": {
          "source": "};",
          "coverage": ""
        },
        "49": {
          "source": "",
          "coverage": ""
        },
        "50": {
          "source": "XDomainRequestWrapper.prototype.send = function(data){",
          "coverage": 2
        },
        "51": {
          "source": "  this.xdr.send(data);",
          "coverage": 0
        },
        "52": {
          "source": "};",
          "coverage": ""
        },
        "53": {
          "source": "",
          "coverage": ""
        },
        "54": {
          "source": "XDomainRequestWrapper.prototype.abort = function(){",
          "coverage": 2
        },
        "55": {
          "source": "  this.xdr.abort();",
          "coverage": 0
        },
        "56": {
          "source": "};",
          "coverage": ""
        },
        "57": {
          "source": "",
          "coverage": ""
        },
        "58": {
          "source": "XDomainRequestWrapper.prototype.setRequestHeader = function(n, v){",
          "coverage": 2
        },
        "59": {
          "source": "  //not supported by xdr",
          "coverage": ""
        },
        "60": {
          "source": "  //Good doc on limitations of XDomainRequest http://blogs.msdn.com/b/ieinternals/archive/2010/05/13/xdomainrequest-restrictions-limitations-and-workarounds.aspx",
          "coverage": ""
        },
        "61": {
          "source": "  //XDomainRequest doesn't allow setting custom request headers. But it is the only available option to do CORS requests in IE8 & 9. In IE10, they finally start to use standard XMLHttpRequest.",
          "coverage": ""
        },
        "62": {
          "source": "  //To support FH auth tokens in IE8&9, we will append them as query parameters, use the key \"fh_headers\"",
          "coverage": ""
        },
        "63": {
          "source": "  this.headers[n] = v;",
          "coverage": 0
        },
        "64": {
          "source": "};",
          "coverage": ""
        },
        "65": {
          "source": "",
          "coverage": ""
        },
        "66": {
          "source": "XDomainRequestWrapper.prototype.getResponseHeader = function(n){",
          "coverage": 2
        },
        "67": {
          "source": "  //not supported by xdr",
          "coverage": ""
        },
        "68": {
          "source": "};",
          "coverage": ""
        },
        "69": {
          "source": "",
          "coverage": ""
        },
        "70": {
          "source": "module.exports = XDomainRequestWrapper;",
          "coverage": 2
        },
        "71": {
          "source": "",
          "coverage": ""
        }
      }
    },
    {
      "filename": "src/modules/ajax.js",
      "coverage": 50.83333333333333,
      "hits": 61,
      "misses": 59,
      "sloc": 120,
      "source": {
        "1": {
          "source": "//a shameless copy from https://github.com/ForbesLindesay/ajax/blob/master/index.js.",
          "coverage": ""
        },
        "2": {
          "source": "//it has the same methods and config options as jQuery/zeptojs but very light weight. see http://api.jquery.com/jQuery.ajax/",
          "coverage": ""
        },
        "3": {
          "source": "//a few small changes are made for supporting IE 8 and other features:",
          "coverage": ""
        },
        "4": {
          "source": "//1. use getXhr function to replace the default XMLHttpRequest implementation for supporting IE8",
          "coverage": ""
        },
        "5": {
          "source": "//2. Integrate with events emitter. So to subscribe ajax events, you can do $fh.on(\"ajaxStart\", handler). See http://api.jquery.com/Ajax_Events/ for full list of events",
          "coverage": ""
        },
        "6": {
          "source": "//3. allow passing xhr factory method through options: e.g. $fh.ajax({xhr: function(){/*own implementation of xhr*/}});",
          "coverage": ""
        },
        "7": {
          "source": "//4. Use fh_timeout value as the default timeout",
          "coverage": ""
        },
        "8": {
          "source": "//5. an extra option called \"tryJSONP\" to allow try the same call with JSONP if normal CORS failed - should only be used internally",
          "coverage": ""
        },
        "9": {
          "source": "//6. for jsonp, allow to specify the callback query param name using the \"jsonp\" option",
          "coverage": ""
        },
        "10": {
          "source": "",
          "coverage": ""
        },
        "11": {
          "source": "var eventsHandler = require(\"./events\");",
          "coverage": 2
        },
        "12": {
          "source": "var XDomainRequestWrapper = require(\"./XDomainRequestWrapper\");",
          "coverage": 2
        },
        "13": {
          "source": "var logger = require(\"./logger\");",
          "coverage": 2
        },
        "14": {
          "source": "",
          "coverage": ""
        },
        "15": {
          "source": "var type",
          "coverage": 2
        },
        "16": {
          "source": "try {",
          "coverage": ""
        },
        "17": {
          "source": "  type = require('type-of')",
          "coverage": 2
        },
        "18": {
          "source": "} catch (ex) {",
          "coverage": ""
        },
        "19": {
          "source": "  //hide from browserify",
          "coverage": ""
        },
        "20": {
          "source": "  var r = require",
          "coverage": 0
        },
        "21": {
          "source": "  type = r('type')",
          "coverage": 0
        },
        "22": {
          "source": "}",
          "coverage": ""
        },
        "23": {
          "source": "",
          "coverage": ""
        },
        "24": {
          "source": "var jsonpID = 0,",
          "coverage": 2
        },
        "25": {
          "source": "  document = window.document,",
          "coverage": ""
        },
        "26": {
          "source": "  key,",
          "coverage": ""
        },
        "27": {
          "source": "  name,",
          "coverage": ""
        },
        "28": {
          "source": "  rscript = /<script\\b[^<]*(?:(?!<\\/script>)<[^<]*)*<\\/script>/gi,",
          "coverage": ""
        },
        "29": {
          "source": "  scriptTypeRE = /^(?:text|application)\\/javascript/i,",
          "coverage": ""
        },
        "30": {
          "source": "  xmlTypeRE = /^(?:text|application)\\/xml/i,",
          "coverage": ""
        },
        "31": {
          "source": "  jsonType = 'application/json',",
          "coverage": ""
        },
        "32": {
          "source": "  htmlType = 'text/html',",
          "coverage": ""
        },
        "33": {
          "source": "  blankRE = /^\\s*$/;",
          "coverage": ""
        },
        "34": {
          "source": "",
          "coverage": ""
        },
        "35": {
          "source": "var ajax = module.exports = function (options) {",
          "coverage": 2
        },
        "36": {
          "source": "  var settings = extend({}, options || {})",
          "coverage": 3
        },
        "37": {
          "source": "  //keep backward compatibility",
          "coverage": ""
        },
        "38": {
          "source": "  if(window && window.$fh && typeof window.$fh.fh_timeout === \"number\"){",
          "coverage": ""
        },
        "39": {
          "source": "    ajax.settings.timeout = window.$fh.fh_timeout;",
          "coverage": 2
        },
        "40": {
          "source": "  }",
          "coverage": ""
        },
        "41": {
          "source": "",
          "coverage": ""
        },
        "42": {
          "source": "  for (key in ajax.settings)",
          "coverage": ""
        },
        "43": {
          "source": "    if (settings[key] === undefined) settings[key] = ajax.settings[key]",
          "coverage": ""
        },
        "44": {
          "source": "",
          "coverage": ""
        },
        "45": {
          "source": "  ajaxStart(settings)",
          "coverage": 3
        },
        "46": {
          "source": "",
          "coverage": ""
        },
        "47": {
          "source": "  if (!settings.crossDomain) {",
          "coverage": ""
        },
        "48": {
          "source": "    settings.crossDomain = /^([\\w-]+:)?\\/\\/([^\\/]+)/.test(settings.url) && (RegExp.$1 != window.location.protocol || RegExp.$2 != window.location.host)",
          "coverage": 3
        },
        "49": {
          "source": "  }",
          "coverage": ""
        },
        "50": {
          "source": "",
          "coverage": ""
        },
        "51": {
          "source": "  var dataType = settings.dataType,",
          "coverage": 3
        },
        "52": {
          "source": "    hasPlaceholder = /=\\?/.test(settings.url)",
          "coverage": ""
        },
        "53": {
          "source": "    if (dataType == 'jsonp' || hasPlaceholder) {",
          "coverage": ""
        },
        "54": {
          "source": "      if (!hasPlaceholder) {",
          "coverage": ""
        },
        "55": {
          "source": "        settings.url = appendQuery(settings.url, (settings.jsonp? settings.jsonp: '_callback') + '=?');",
          "coverage": 0
        },
        "56": {
          "source": "      }",
          "coverage": ""
        },
        "57": {
          "source": "      return ajax.JSONP(settings)",
          "coverage": 0
        },
        "58": {
          "source": "    }",
          "coverage": ""
        },
        "59": {
          "source": "",
          "coverage": ""
        },
        "60": {
          "source": "  if (!settings.url) settings.url = window.location.toString()",
          "coverage": ""
        },
        "61": {
          "source": "  serializeData(settings)",
          "coverage": 3
        },
        "62": {
          "source": "",
          "coverage": ""
        },
        "63": {
          "source": "  var mime = settings.accepts[dataType],",
          "coverage": 3
        },
        "64": {
          "source": "    baseHeaders = {},",
          "coverage": ""
        },
        "65": {
          "source": "    protocol = /^([\\w-]+:)\\/\\//.test(settings.url) ? RegExp.$1 : window.location.protocol,",
          "coverage": ""
        },
        "66": {
          "source": "    xhr = settings.xhr(settings.crossDomain),",
          "coverage": ""
        },
        "67": {
          "source": "    abortTimeout = null;",
          "coverage": ""
        },
        "68": {
          "source": "",
          "coverage": ""
        },
        "69": {
          "source": "  if (!settings.crossDomain) baseHeaders['X-Requested-With'] = 'XMLHttpRequest'",
          "coverage": ""
        },
        "70": {
          "source": "  if (mime) {",
          "coverage": ""
        },
        "71": {
          "source": "    baseHeaders['Accept'] = mime",
          "coverage": 3
        },
        "72": {
          "source": "    if (mime.indexOf(',') > -1) mime = mime.split(',', 2)[0]",
          "coverage": ""
        },
        "73": {
          "source": "    xhr.overrideMimeType && xhr.overrideMimeType(mime)",
          "coverage": 3
        },
        "74": {
          "source": "  }",
          "coverage": ""
        },
        "75": {
          "source": "  if (settings.contentType || (settings.data && !settings.formdata && settings.type.toUpperCase() != 'GET'))",
          "coverage": ""
        },
        "76": {
          "source": "    baseHeaders['Content-Type'] = (settings.contentType || 'application/x-www-form-urlencoded')",
          "coverage": ""
        },
        "77": {
          "source": "  settings.headers = extend(baseHeaders, settings.headers || {})",
          "coverage": 3
        },
        "78": {
          "source": "",
          "coverage": ""
        },
        "79": {
          "source": "  if (typeof Titanium !== 'undefined') {",
          "coverage": ""
        },
        "80": {
          "source": "    xhr.onerror  = function(){",
          "coverage": 0
        },
        "81": {
          "source": "      if (!abortTimeout){",
          "coverage": ""
        },
        "82": {
          "source": "        return;",
          "coverage": 0
        },
        "83": {
          "source": "      }",
          "coverage": ""
        },
        "84": {
          "source": "      clearTimeout(abortTimeout);",
          "coverage": 0
        },
        "85": {
          "source": "      ajaxError(null, 'error', xhr, settings);",
          "coverage": 0
        },
        "86": {
          "source": "    };",
          "coverage": ""
        },
        "87": {
          "source": "  }",
          "coverage": ""
        },
        "88": {
          "source": "",
          "coverage": ""
        },
        "89": {
          "source": "  xhr.onreadystatechange = function () {",
          "coverage": 3
        },
        "90": {
          "source": "",
          "coverage": ""
        },
        "91": {
          "source": "    if (xhr.readyState == 4) {",
          "coverage": ""
        },
        "92": {
          "source": "      clearTimeout(abortTimeout)",
          "coverage": 3
        },
        "93": {
          "source": "      abortTimeout = undefined;",
          "coverage": 3
        },
        "94": {
          "source": "      var result, error = false",
          "coverage": 3
        },
        "95": {
          "source": "      if(settings.tryJSONP){",
          "coverage": ""
        },
        "96": {
          "source": "        //check if the request has fail. In some cases, we may want to try jsonp as well. Again, FH only...",
          "coverage": ""
        },
        "97": {
          "source": "        if(xhr.status === 0 && settings.crossDomain && !xhr.isTimeout &&  protocol != 'file:'){",
          "coverage": ""
        },
        "98": {
          "source": "          logger.debug(\"retry ajax call with jsonp\")",
          "coverage": 0
        },
        "99": {
          "source": "          settings.type = \"GET\";",
          "coverage": 0
        },
        "100": {
          "source": "          settings.dataType = \"jsonp\";",
          "coverage": 0
        },
        "101": {
          "source": "",
          "coverage": ""
        },
        "102": {
          "source": "          if (settings.data) {",
          "coverage": ""
        },
        "103": {
          "source": "            settings.data = \"_jsonpdata=\" + JSON.stringify(",
          "coverage": 0
        },
        "104": {
          "source": "              require(\"./fhparams\").addFHParams(JSON.parse(settings.data))",
          "coverage": ""
        },
        "105": {
          "source": "            );",
          "coverage": ""
        },
        "106": {
          "source": "          } else {",
          "coverage": ""
        },
        "107": {
          "source": "            settings.data = \"_jsonpdata=\" + settings.data;",
          "coverage": 0
        },
        "108": {
          "source": "          }",
          "coverage": ""
        },
        "109": {
          "source": "",
          "coverage": ""
        },
        "110": {
          "source": "          return ajax(settings);",
          "coverage": 0
        },
        "111": {
          "source": "        }",
          "coverage": ""
        },
        "112": {
          "source": "      }",
          "coverage": ""
        },
        "113": {
          "source": "      if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304 || (xhr.status == 0 && protocol == 'file:')) {",
          "coverage": ""
        },
        "114": {
          "source": "        dataType = dataType || mimeToDataType(xhr.getResponseHeader('content-type'))",
          "coverage": 2
        },
        "115": {
          "source": "        result = xhr.responseText",
          "coverage": 2
        },
        "116": {
          "source": "        logger.debug(\"ajax response :: status = \" + xhr.status + \" :: body = \" + result)",
          "coverage": 2
        },
        "117": {
          "source": "",
          "coverage": ""
        },
        "118": {
          "source": "        try {",
          "coverage": ""
        },
        "119": {
          "source": "          if (dataType == 'script')(1, eval)(result)",
          "coverage": ""
        },
        "120": {
          "source": "          else if (dataType == 'xml') result = xhr.responseXML",
          "coverage": ""
        },
        "121": {
          "source": "          else if (dataType == 'json') result = blankRE.test(result) ? null : JSON.parse(result)",
          "coverage": ""
        },
        "122": {
          "source": "        } catch (e) {",
          "coverage": ""
        },
        "123": {
          "source": "          error = e",
          "coverage": 0
        },
        "124": {
          "source": "        }",
          "coverage": ""
        },
        "125": {
          "source": "",
          "coverage": ""
        },
        "126": {
          "source": "        if (error) {",
          "coverage": ""
        },
        "127": {
          "source": "          logger.debug(\"ajax error\", error);",
          "coverage": 0
        },
        "128": {
          "source": "          ajaxError(error, 'parsererror', xhr, settings)",
          "coverage": 0
        },
        "129": {
          "source": "        }",
          "coverage": ""
        },
        "130": {
          "source": "        else ajaxSuccess(result, xhr, settings)",
          "coverage": ""
        },
        "131": {
          "source": "      } else {",
          "coverage": ""
        },
        "132": {
          "source": "        ajaxError(null, 'error', xhr, settings)",
          "coverage": 1
        },
        "133": {
          "source": "      }",
          "coverage": ""
        },
        "134": {
          "source": "    }",
          "coverage": ""
        },
        "135": {
          "source": "  }",
          "coverage": ""
        },
        "136": {
          "source": "",
          "coverage": ""
        },
        "137": {
          "source": "  var async = 'async' in settings ? settings.async : true",
          "coverage": 3
        },
        "138": {
          "source": "  logger.debug(\"ajax call settings\", settings)",
          "coverage": 3
        },
        "139": {
          "source": "  xhr.open(settings.type, settings.url, async)",
          "coverage": 3
        },
        "140": {
          "source": "",
          "coverage": ""
        },
        "141": {
          "source": "  for (name in settings.headers) xhr.setRequestHeader(name, settings.headers[name])",
          "coverage": ""
        },
        "142": {
          "source": "",
          "coverage": ""
        },
        "143": {
          "source": "  if (ajaxBeforeSend(xhr, settings) === false) {",
          "coverage": ""
        },
        "144": {
          "source": "    logger.debug(\"ajax call is aborted due to ajaxBeforeSend\")",
          "coverage": 0
        },
        "145": {
          "source": "    xhr.abort()",
          "coverage": 0
        },
        "146": {
          "source": "    return false",
          "coverage": 0
        },
        "147": {
          "source": "  }",
          "coverage": ""
        },
        "148": {
          "source": "",
          "coverage": ""
        },
        "149": {
          "source": "  if (settings.timeout > 0) abortTimeout = setTimeout(function () {",
          "coverage": ""
        },
        "150": {
          "source": "    logger.debug(\"ajax call timed out\")",
          "coverage": 0
        },
        "151": {
          "source": "    xhr.onreadystatechange = empty",
          "coverage": 0
        },
        "152": {
          "source": "    xhr.abort()",
          "coverage": 0
        },
        "153": {
          "source": "    xhr.isTimeout = true",
          "coverage": 0
        },
        "154": {
          "source": "    ajaxError(null, 'timeout', xhr, settings)",
          "coverage": 0
        },
        "155": {
          "source": "  }, settings.timeout)",
          "coverage": ""
        },
        "156": {
          "source": "",
          "coverage": ""
        },
        "157": {
          "source": "  // avoid sending empty string (#319)",
          "coverage": ""
        },
        "158": {
          "source": "  xhr.send(settings.data ? settings.data : null)",
          "coverage": 3
        },
        "159": {
          "source": "  return xhr",
          "coverage": 3
        },
        "160": {
          "source": "}",
          "coverage": ""
        },
        "161": {
          "source": "",
          "coverage": ""
        },
        "162": {
          "source": "",
          "coverage": ""
        },
        "163": {
          "source": "// trigger a custom event and return true",
          "coverage": ""
        },
        "164": {
          "source": "function triggerAndReturn(context, eventName, data) {",
          "coverage": ""
        },
        "165": {
          "source": "  eventsHandler.emit(eventName, data);",
          "coverage": 15
        },
        "166": {
          "source": "  return true;",
          "coverage": 15
        },
        "167": {
          "source": "}",
          "coverage": ""
        },
        "168": {
          "source": "",
          "coverage": ""
        },
        "169": {
          "source": "// trigger an Ajax \"global\" event",
          "coverage": ""
        },
        "170": {
          "source": "function triggerGlobal(settings, context, eventName, data) {",
          "coverage": ""
        },
        "171": {
          "source": "  if (settings.global) return triggerAndReturn(context || document, eventName, data)",
          "coverage": ""
        },
        "172": {
          "source": "}",
          "coverage": ""
        },
        "173": {
          "source": "",
          "coverage": ""
        },
        "174": {
          "source": "// Number of active Ajax requests",
          "coverage": ""
        },
        "175": {
          "source": "ajax.active = 0",
          "coverage": 2
        },
        "176": {
          "source": "",
          "coverage": ""
        },
        "177": {
          "source": "function ajaxStart(settings) {",
          "coverage": ""
        },
        "178": {
          "source": "  if (settings.global && ajax.active++ === 0) triggerGlobal(settings, null, 'ajaxStart')",
          "coverage": ""
        },
        "179": {
          "source": "}",
          "coverage": ""
        },
        "180": {
          "source": "",
          "coverage": ""
        },
        "181": {
          "source": "function ajaxStop(settings) {",
          "coverage": ""
        },
        "182": {
          "source": "  if (settings.global && !(--ajax.active)) triggerGlobal(settings, null, 'ajaxStop')",
          "coverage": ""
        },
        "183": {
          "source": "}",
          "coverage": ""
        },
        "184": {
          "source": "",
          "coverage": ""
        },
        "185": {
          "source": "// triggers an extra global event \"ajaxBeforeSend\" that's like \"ajaxSend\" but cancelable",
          "coverage": ""
        },
        "186": {
          "source": "function ajaxBeforeSend(xhr, settings) {",
          "coverage": ""
        },
        "187": {
          "source": "  var context = settings.context",
          "coverage": 3
        },
        "188": {
          "source": "  if (settings.beforeSend.call(context, xhr, settings) === false)",
          "coverage": ""
        },
        "189": {
          "source": "    return false",
          "coverage": ""
        },
        "190": {
          "source": "",
          "coverage": ""
        },
        "191": {
          "source": "  triggerGlobal(settings, context, 'ajaxSend', [xhr, settings])",
          "coverage": 3
        },
        "192": {
          "source": "}",
          "coverage": ""
        },
        "193": {
          "source": "",
          "coverage": ""
        },
        "194": {
          "source": "function ajaxSuccess(data, xhr, settings) {",
          "coverage": ""
        },
        "195": {
          "source": "  var context = settings.context,",
          "coverage": 2
        },
        "196": {
          "source": "    status = 'success'",
          "coverage": ""
        },
        "197": {
          "source": "  settings.success.call(context, data, status, xhr)",
          "coverage": 2
        },
        "198": {
          "source": "  triggerGlobal(settings, context, 'ajaxSuccess', [xhr, settings, data])",
          "coverage": 2
        },
        "199": {
          "source": "  ajaxComplete(status, xhr, settings)",
          "coverage": 2
        },
        "200": {
          "source": "}",
          "coverage": ""
        },
        "201": {
          "source": "// type: \"timeout\", \"error\", \"abort\", \"parsererror\"",
          "coverage": ""
        },
        "202": {
          "source": "function ajaxError(error, type, xhr, settings) {",
          "coverage": ""
        },
        "203": {
          "source": "  var context = settings.context",
          "coverage": 1
        },
        "204": {
          "source": "  settings.error.call(context, xhr, type, error)",
          "coverage": 1
        },
        "205": {
          "source": "  triggerGlobal(settings, context, 'ajaxError', [xhr, settings, error])",
          "coverage": 1
        },
        "206": {
          "source": "  ajaxComplete(type, xhr, settings)",
          "coverage": 1
        },
        "207": {
          "source": "}",
          "coverage": ""
        },
        "208": {
          "source": "// status: \"success\", \"notmodified\", \"error\", \"timeout\", \"abort\", \"parsererror\"",
          "coverage": ""
        },
        "209": {
          "source": "function ajaxComplete(status, xhr, settings) {",
          "coverage": ""
        },
        "210": {
          "source": "  var context = settings.context",
          "coverage": 3
        },
        "211": {
          "source": "  settings.complete.call(context, xhr, status)",
          "coverage": 3
        },
        "212": {
          "source": "  triggerGlobal(settings, context, 'ajaxComplete', [xhr, settings])",
          "coverage": 3
        },
        "213": {
          "source": "  ajaxStop(settings)",
          "coverage": 3
        },
        "214": {
          "source": "}",
          "coverage": ""
        },
        "215": {
          "source": "",
          "coverage": ""
        },
        "216": {
          "source": "// Empty function, used as default callback",
          "coverage": ""
        },
        "217": {
          "source": "function empty() {}",
          "coverage": ""
        },
        "218": {
          "source": "",
          "coverage": ""
        },
        "219": {
          "source": "ajax.JSONP = function (options) {",
          "coverage": 2
        },
        "220": {
          "source": "  if (!('type' in options)) return ajax(options)",
          "coverage": ""
        },
        "221": {
          "source": "",
          "coverage": ""
        },
        "222": {
          "source": "  var callbackName = 'jsonp' + (++jsonpID),",
          "coverage": 0
        },
        "223": {
          "source": "    script = document.createElement('script'),",
          "coverage": ""
        },
        "224": {
          "source": "    abort = function () {",
          "coverage": ""
        },
        "225": {
          "source": "      //todo: remove script",
          "coverage": ""
        },
        "226": {
          "source": "      //$(script).remove()",
          "coverage": ""
        },
        "227": {
          "source": "      if (callbackName in window) window[callbackName] = empty",
          "coverage": ""
        },
        "228": {
          "source": "      ajaxComplete('abort', xhr, options)",
          "coverage": 0
        },
        "229": {
          "source": "    },",
          "coverage": ""
        },
        "230": {
          "source": "    xhr = {",
          "coverage": ""
        },
        "231": {
          "source": "      abort: abort",
          "coverage": ""
        },
        "232": {
          "source": "    }, abortTimeout,",
          "coverage": ""
        },
        "233": {
          "source": "    head = document.getElementsByTagName(\"head\")[0] || document.documentElement",
          "coverage": ""
        },
        "234": {
          "source": "",
          "coverage": ""
        },
        "235": {
          "source": "  if (options.error) script.onerror = function () {",
          "coverage": ""
        },
        "236": {
          "source": "    xhr.abort()",
          "coverage": 0
        },
        "237": {
          "source": "    options.error()",
          "coverage": 0
        },
        "238": {
          "source": "  }",
          "coverage": ""
        },
        "239": {
          "source": "",
          "coverage": ""
        },
        "240": {
          "source": "  window[callbackName] = function (data) {",
          "coverage": 0
        },
        "241": {
          "source": "    clearTimeout(abortTimeout)",
          "coverage": 0
        },
        "242": {
          "source": "    abortTimeout = undefined;",
          "coverage": 0
        },
        "243": {
          "source": "    //todo: remove script",
          "coverage": ""
        },
        "244": {
          "source": "    //$(script).remove()",
          "coverage": ""
        },
        "245": {
          "source": "    delete window[callbackName]",
          "coverage": 0
        },
        "246": {
          "source": "    ajaxSuccess(data, xhr, options)",
          "coverage": 0
        },
        "247": {
          "source": "  }",
          "coverage": ""
        },
        "248": {
          "source": "",
          "coverage": ""
        },
        "249": {
          "source": "  serializeData(options)",
          "coverage": 0
        },
        "250": {
          "source": "  script.src = options.url.replace(/=\\?/, '=' + callbackName)",
          "coverage": 0
        },
        "251": {
          "source": "",
          "coverage": ""
        },
        "252": {
          "source": "  // Use insertBefore instead of appendChild to circumvent an IE6 bug.",
          "coverage": ""
        },
        "253": {
          "source": "  // This arises when a base node is used (see jQuery bugs #2709 and #4378).",
          "coverage": ""
        },
        "254": {
          "source": "  head.insertBefore(script, head.firstChild);",
          "coverage": 0
        },
        "255": {
          "source": "",
          "coverage": ""
        },
        "256": {
          "source": "  if (options.timeout > 0) abortTimeout = setTimeout(function () {",
          "coverage": ""
        },
        "257": {
          "source": "    xhr.abort()",
          "coverage": 0
        },
        "258": {
          "source": "    ajaxComplete('timeout', xhr, options)",
          "coverage": 0
        },
        "259": {
          "source": "  }, options.timeout)",
          "coverage": ""
        },
        "260": {
          "source": "",
          "coverage": ""
        },
        "261": {
          "source": "  return xhr",
          "coverage": 0
        },
        "262": {
          "source": "}",
          "coverage": ""
        },
        "263": {
          "source": "",
          "coverage": ""
        },
        "264": {
          "source": "function isIE(){",
          "coverage": ""
        },
        "265": {
          "source": "  var ie = false;",
          "coverage": 3
        },
        "266": {
          "source": "  if(navigator.userAgent && navigator.userAgent.indexOf(\"MSIE\") >=0 ){",
          "coverage": ""
        },
        "267": {
          "source": "    ie = true;",
          "coverage": 0
        },
        "268": {
          "source": "  }",
          "coverage": ""
        },
        "269": {
          "source": "  return ie;",
          "coverage": 3
        },
        "270": {
          "source": "}",
          "coverage": ""
        },
        "271": {
          "source": "",
          "coverage": ""
        },
        "272": {
          "source": "function getXhr(crossDomain){",
          "coverage": ""
        },
        "273": {
          "source": "  var xhr = null;",
          "coverage": 3
        },
        "274": {
          "source": "  //always use XMLHttpRequest if available",
          "coverage": ""
        },
        "275": {
          "source": "  if(window.XMLHttpRequest){",
          "coverage": ""
        },
        "276": {
          "source": "    xhr = new XMLHttpRequest();",
          "coverage": 3
        },
        "277": {
          "source": "  }",
          "coverage": ""
        },
        "278": {
          "source": "  //for IE8 only. Need to make sure it's not used when running inside Cordova.",
          "coverage": ""
        },
        "279": {
          "source": "  if(isIE() && (crossDomain === true) && typeof window.XDomainRequest !== \"undefined\" && typeof window.cordova === \"undefined\"){",
          "coverage": ""
        },
        "280": {
          "source": "    xhr = new XDomainRequestWrapper(new XDomainRequest());",
          "coverage": 0
        },
        "281": {
          "source": "  }",
          "coverage": ""
        },
        "282": {
          "source": "  // For Titanium SDK",
          "coverage": ""
        },
        "283": {
          "source": "  if (typeof Titanium !== 'undefined'){",
          "coverage": ""
        },
        "284": {
          "source": "    var params = {};",
          "coverage": 0
        },
        "285": {
          "source": "    if(ajax.settings && ajax.settings.timeout){",
          "coverage": ""
        },
        "286": {
          "source": "      params.timeout = ajax.settings.timeout;",
          "coverage": 0
        },
        "287": {
          "source": "    }",
          "coverage": ""
        },
        "288": {
          "source": "    xhr = Titanium.Network.createHTTPClient(params);",
          "coverage": 0
        },
        "289": {
          "source": "  }",
          "coverage": ""
        },
        "290": {
          "source": "",
          "coverage": ""
        },
        "291": {
          "source": "  return xhr;",
          "coverage": 3
        },
        "292": {
          "source": "}",
          "coverage": ""
        },
        "293": {
          "source": "",
          "coverage": ""
        },
        "294": {
          "source": "ajax.settings = {",
          "coverage": 2
        },
        "295": {
          "source": "  // Default type of request",
          "coverage": ""
        },
        "296": {
          "source": "  type: 'GET',",
          "coverage": ""
        },
        "297": {
          "source": "  // Callback that is executed before request",
          "coverage": ""
        },
        "298": {
          "source": "  beforeSend: empty,",
          "coverage": ""
        },
        "299": {
          "source": "  // Callback that is executed if the request succeeds",
          "coverage": ""
        },
        "300": {
          "source": "  success: empty,",
          "coverage": ""
        },
        "301": {
          "source": "  // Callback that is executed the the server drops error",
          "coverage": ""
        },
        "302": {
          "source": "  error: empty,",
          "coverage": ""
        },
        "303": {
          "source": "  // Callback that is executed on request complete (both: error and success)",
          "coverage": ""
        },
        "304": {
          "source": "  complete: empty,",
          "coverage": ""
        },
        "305": {
          "source": "  // The context for the callbacks",
          "coverage": ""
        },
        "306": {
          "source": "  context: null,",
          "coverage": ""
        },
        "307": {
          "source": "  // Whether to trigger \"global\" Ajax events",
          "coverage": ""
        },
        "308": {
          "source": "  global: true,",
          "coverage": ""
        },
        "309": {
          "source": "  // Transport",
          "coverage": ""
        },
        "310": {
          "source": "  xhr: getXhr,",
          "coverage": ""
        },
        "311": {
          "source": "  // MIME types mapping",
          "coverage": ""
        },
        "312": {
          "source": "  accepts: {",
          "coverage": ""
        },
        "313": {
          "source": "    script: 'text/javascript, application/javascript',",
          "coverage": ""
        },
        "314": {
          "source": "    json: jsonType,",
          "coverage": ""
        },
        "315": {
          "source": "    xml: 'application/xml, text/xml',",
          "coverage": ""
        },
        "316": {
          "source": "    html: htmlType,",
          "coverage": ""
        },
        "317": {
          "source": "    text: 'text/plain'",
          "coverage": ""
        },
        "318": {
          "source": "  },",
          "coverage": ""
        },
        "319": {
          "source": "  // Whether the request is to another domain",
          "coverage": ""
        },
        "320": {
          "source": "  crossDomain: false",
          "coverage": ""
        },
        "321": {
          "source": "}",
          "coverage": ""
        },
        "322": {
          "source": "",
          "coverage": ""
        },
        "323": {
          "source": "function mimeToDataType(mime) {",
          "coverage": ""
        },
        "324": {
          "source": "  return mime && (mime == htmlType ? 'html' :",
          "coverage": 0
        },
        "325": {
          "source": "    mime == jsonType ? 'json' :",
          "coverage": ""
        },
        "326": {
          "source": "    scriptTypeRE.test(mime) ? 'script' :",
          "coverage": ""
        },
        "327": {
          "source": "    xmlTypeRE.test(mime) && 'xml') || 'text'",
          "coverage": ""
        },
        "328": {
          "source": "}",
          "coverage": ""
        },
        "329": {
          "source": "",
          "coverage": ""
        },
        "330": {
          "source": "function appendQuery(url, query) {",
          "coverage": ""
        },
        "331": {
          "source": "  return (url + '&' + query).replace(/[&?]{1,2}/, '?')",
          "coverage": 0
        },
        "332": {
          "source": "}",
          "coverage": ""
        },
        "333": {
          "source": "",
          "coverage": ""
        },
        "334": {
          "source": "// serialize payload and append it to the URL for GET requests",
          "coverage": ""
        },
        "335": {
          "source": "function serializeData(options) {",
          "coverage": ""
        },
        "336": {
          "source": "  if (type(options.data) === 'object') {",
          "coverage": ""
        },
        "337": {
          "source": "    if(typeof options.data.append === \"function\"){",
          "coverage": ""
        },
        "338": {
          "source": "      //we are dealing with FormData, do not serialize",
          "coverage": ""
        },
        "339": {
          "source": "      options.formdata = true;",
          "coverage": 0
        },
        "340": {
          "source": "    } else {",
          "coverage": ""
        },
        "341": {
          "source": "      options.data = param(options.data)",
          "coverage": 0
        },
        "342": {
          "source": "    }",
          "coverage": ""
        },
        "343": {
          "source": "  }",
          "coverage": ""
        },
        "344": {
          "source": "  if (options.data && (!options.type || options.type.toUpperCase() == 'GET'))",
          "coverage": ""
        },
        "345": {
          "source": "    options.url = appendQuery(options.url, options.data)",
          "coverage": ""
        },
        "346": {
          "source": "}",
          "coverage": ""
        },
        "347": {
          "source": "",
          "coverage": ""
        },
        "348": {
          "source": "ajax.get = function (url, success) {",
          "coverage": 2
        },
        "349": {
          "source": "  return ajax({",
          "coverage": 0
        },
        "350": {
          "source": "    url: url,",
          "coverage": ""
        },
        "351": {
          "source": "    success: success",
          "coverage": ""
        },
        "352": {
          "source": "  })",
          "coverage": ""
        },
        "353": {
          "source": "}",
          "coverage": ""
        },
        "354": {
          "source": "",
          "coverage": ""
        },
        "355": {
          "source": "ajax.post = function (url, data, success, dataType) {",
          "coverage": 2
        },
        "356": {
          "source": "  if (type(data) === 'function') dataType = dataType || success, success = data, data = null",
          "coverage": ""
        },
        "357": {
          "source": "  return ajax({",
          "coverage": 0
        },
        "358": {
          "source": "    type: 'POST',",
          "coverage": ""
        },
        "359": {
          "source": "    url: url,",
          "coverage": ""
        },
        "360": {
          "source": "    data: data,",
          "coverage": ""
        },
        "361": {
          "source": "    success: success,",
          "coverage": ""
        },
        "362": {
          "source": "    dataType: dataType",
          "coverage": ""
        },
        "363": {
          "source": "  })",
          "coverage": ""
        },
        "364": {
          "source": "}",
          "coverage": ""
        },
        "365": {
          "source": "",
          "coverage": ""
        },
        "366": {
          "source": "ajax.getJSON = function (url, success) {",
          "coverage": 2
        },
        "367": {
          "source": "  return ajax({",
          "coverage": 0
        },
        "368": {
          "source": "    url: url,",
          "coverage": ""
        },
        "369": {
          "source": "    success: success,",
          "coverage": ""
        },
        "370": {
          "source": "    dataType: 'json'",
          "coverage": ""
        },
        "371": {
          "source": "  })",
          "coverage": ""
        },
        "372": {
          "source": "}",
          "coverage": ""
        },
        "373": {
          "source": "",
          "coverage": ""
        },
        "374": {
          "source": "var escape = encodeURIComponent;",
          "coverage": 2
        },
        "375": {
          "source": "",
          "coverage": ""
        },
        "376": {
          "source": "function serialize(params, obj, traditional, scope) {",
          "coverage": ""
        },
        "377": {
          "source": "  var array = type(obj) === 'array';",
          "coverage": 0
        },
        "378": {
          "source": "  for (var key in obj) {",
          "coverage": ""
        },
        "379": {
          "source": "    var value = obj[key];",
          "coverage": 0
        },
        "380": {
          "source": "",
          "coverage": ""
        },
        "381": {
          "source": "    if (scope) key = traditional ? scope : scope + '[' + (array ? '' : key) + ']'",
          "coverage": ""
        },
        "382": {
          "source": "    // handle data in serializeArray() format",
          "coverage": ""
        },
        "383": {
          "source": "    if (!scope && array) params.add(value.name, value.value)",
          "coverage": ""
        },
        "384": {
          "source": "    // recurse into nested objects",
          "coverage": ""
        },
        "385": {
          "source": "    else if (traditional ? (type(value) === 'array') : (type(value) === 'object'))",
          "coverage": ""
        },
        "386": {
          "source": "      serialize(params, value, traditional, key)",
          "coverage": ""
        },
        "387": {
          "source": "    else params.add(key, value)",
          "coverage": ""
        },
        "388": {
          "source": "  }",
          "coverage": ""
        },
        "389": {
          "source": "}",
          "coverage": ""
        },
        "390": {
          "source": "",
          "coverage": ""
        },
        "391": {
          "source": "function param(obj, traditional) {",
          "coverage": ""
        },
        "392": {
          "source": "  var params = []",
          "coverage": 0
        },
        "393": {
          "source": "  params.add = function (k, v) {",
          "coverage": 0
        },
        "394": {
          "source": "    this.push(escape(k) + '=' + escape(v))",
          "coverage": 0
        },
        "395": {
          "source": "  }",
          "coverage": ""
        },
        "396": {
          "source": "  serialize(params, obj, traditional)",
          "coverage": 0
        },
        "397": {
          "source": "  return params.join('&').replace('%20', '+')",
          "coverage": 0
        },
        "398": {
          "source": "}",
          "coverage": ""
        },
        "399": {
          "source": "",
          "coverage": ""
        },
        "400": {
          "source": "function extend(target) {",
          "coverage": ""
        },
        "401": {
          "source": "  var slice = Array.prototype.slice;",
          "coverage": 6
        },
        "402": {
          "source": "  slice.call(arguments, 1).forEach(function (source) {",
          "coverage": 6
        },
        "403": {
          "source": "    for (key in source)",
          "coverage": ""
        },
        "404": {
          "source": "      if (source[key] !== undefined)",
          "coverage": ""
        },
        "405": {
          "source": "        target[key] = source[key]",
          "coverage": ""
        },
        "406": {
          "source": "  })",
          "coverage": ""
        },
        "407": {
          "source": "  return target",
          "coverage": 6
        },
        "408": {
          "source": "}",
          "coverage": ""
        },
        "409": {
          "source": "",
          "coverage": ""
        }
      }
    },
    {
      "filename": "src/modules/api_act.js",
      "coverage": 34.78260869565217,
      "hits": 8,
      "misses": 15,
      "sloc": 23,
      "source": {
        "1": {
          "source": "var logger =require(\"./logger\");",
          "coverage": 1
        },
        "2": {
          "source": "var cloud = require(\"./waitForCloud\");",
          "coverage": 1
        },
        "3": {
          "source": "var fhparams = require(\"./fhparams\");",
          "coverage": 1
        },
        "4": {
          "source": "var ajax = require(\"./ajax\");",
          "coverage": 1
        },
        "5": {
          "source": "var handleError = require(\"./handleError\");",
          "coverage": 1
        },
        "6": {
          "source": "var appProps = require(\"./appProps\");",
          "coverage": 1
        },
        "7": {
          "source": "var _ = require('underscore');",
          "coverage": 1
        },
        "8": {
          "source": "",
          "coverage": ""
        },
        "9": {
          "source": "function doActCall(opts, success, fail){",
          "coverage": ""
        },
        "10": {
          "source": "  var cloud_host = cloud.getCloudHost();",
          "coverage": 0
        },
        "11": {
          "source": "  var url = cloud_host.getActUrl(opts.act);",
          "coverage": 0
        },
        "12": {
          "source": "  var params = opts.req || {};",
          "coverage": 0
        },
        "13": {
          "source": "  var headers = fhparams.getFHHeaders();",
          "coverage": 0
        },
        "14": {
          "source": "  if (opts.headers) {",
          "coverage": ""
        },
        "15": {
          "source": "    headers = _.extend(headers, opts.headers);",
          "coverage": 0
        },
        "16": {
          "source": "  }",
          "coverage": ""
        },
        "17": {
          "source": "  return ajax({",
          "coverage": 0
        },
        "18": {
          "source": "    \"url\": url,",
          "coverage": ""
        },
        "19": {
          "source": "    \"tryJSONP\": true,",
          "coverage": ""
        },
        "20": {
          "source": "    \"type\": \"POST\",",
          "coverage": ""
        },
        "21": {
          "source": "    \"dataType\": \"json\",",
          "coverage": ""
        },
        "22": {
          "source": "    \"data\": JSON.stringify(params),",
          "coverage": ""
        },
        "23": {
          "source": "    \"headers\": headers,",
          "coverage": ""
        },
        "24": {
          "source": "    \"contentType\": \"application/json\",",
          "coverage": ""
        },
        "25": {
          "source": "    \"timeout\": opts.timeout || appProps.timeout,",
          "coverage": ""
        },
        "26": {
          "source": "    \"success\": success,",
          "coverage": ""
        },
        "27": {
          "source": "    \"error\": function(req, statusText, error){",
          "coverage": ""
        },
        "28": {
          "source": "      return handleError(fail, req, statusText, error);",
          "coverage": 0
        },
        "29": {
          "source": "    }",
          "coverage": ""
        },
        "30": {
          "source": "  });",
          "coverage": ""
        },
        "31": {
          "source": "}",
          "coverage": ""
        },
        "32": {
          "source": "",
          "coverage": ""
        },
        "33": {
          "source": "module.exports = function(opts, success, fail){",
          "coverage": 1
        },
        "34": {
          "source": "  logger.debug(\"act is called\");",
          "coverage": 0
        },
        "35": {
          "source": "  if(!fail){",
          "coverage": ""
        },
        "36": {
          "source": "    fail = function(msg, error){",
          "coverage": 0
        },
        "37": {
          "source": "      logger.debug(msg + \":\" + JSON.stringify(error));",
          "coverage": 0
        },
        "38": {
          "source": "    };",
          "coverage": ""
        },
        "39": {
          "source": "  }",
          "coverage": ""
        },
        "40": {
          "source": "",
          "coverage": ""
        },
        "41": {
          "source": "  if(!opts.act){",
          "coverage": ""
        },
        "42": {
          "source": "    return fail('act_no_action', {});",
          "coverage": 0
        },
        "43": {
          "source": "  }",
          "coverage": ""
        },
        "44": {
          "source": "",
          "coverage": ""
        },
        "45": {
          "source": "  cloud.ready(function(err, cloudHost){",
          "coverage": 0
        },
        "46": {
          "source": "    logger.debug(\"Calling fhact now\");",
          "coverage": 0
        },
        "47": {
          "source": "    if(err){",
          "coverage": ""
        },
        "48": {
          "source": "      return fail(err.message, err);",
          "coverage": 0
        },
        "49": {
          "source": "    } else {",
          "coverage": ""
        },
        "50": {
          "source": "      doActCall(opts, success, fail);",
          "coverage": 0
        },
        "51": {
          "source": "    }",
          "coverage": ""
        },
        "52": {
          "source": "  });",
          "coverage": ""
        },
        "53": {
          "source": "};",
          "coverage": ""
        },
        "54": {
          "source": "",
          "coverage": ""
        }
      }
    },
    {
      "filename": "src/modules/api_auth.js",
      "coverage": 28.57142857142857,
      "hits": 16,
      "misses": 40,
      "sloc": 56,
      "source": {
        "1": {
          "source": "var logger = require(\"./logger\");",
          "coverage": 1
        },
        "2": {
          "source": "var cloud = require(\"./waitForCloud\");",
          "coverage": 1
        },
        "3": {
          "source": "var fhparams = require(\"./fhparams\");",
          "coverage": 1
        },
        "4": {
          "source": "var ajax = require(\"./ajax\");",
          "coverage": 1
        },
        "5": {
          "source": "var handleError = require(\"./handleError\");",
          "coverage": 1
        },
        "6": {
          "source": "var device = require(\"./device\");",
          "coverage": 1
        },
        "7": {
          "source": "var constants = require(\"./constants\");",
          "coverage": 1
        },
        "8": {
          "source": "var checkAuth = require(\"./checkAuth\");",
          "coverage": 1
        },
        "9": {
          "source": "var appProps = require(\"./appProps\");",
          "coverage": 1
        },
        "10": {
          "source": "var data = require('./data');",
          "coverage": 1
        },
        "11": {
          "source": "",
          "coverage": ""
        },
        "12": {
          "source": "function callAuthEndpoint(endpoint, data, opts, success, fail){",
          "coverage": ""
        },
        "13": {
          "source": "  var app_props = appProps.getAppProps();",
          "coverage": 0
        },
        "14": {
          "source": "  var path = app_props.host + constants.boxprefix + \"admin/authpolicy/\" + endpoint;",
          "coverage": 0
        },
        "15": {
          "source": "",
          "coverage": ""
        },
        "16": {
          "source": "  if (app_props.local) {",
          "coverage": ""
        },
        "17": {
          "source": "    path = cloud.getCloudHostUrl() + constants.boxprefix + \"admin/authpolicy/\" + endpoint;",
          "coverage": 0
        },
        "18": {
          "source": "  }",
          "coverage": ""
        },
        "19": {
          "source": "",
          "coverage": ""
        },
        "20": {
          "source": "  ajax({",
          "coverage": 0
        },
        "21": {
          "source": "    \"url\": path,",
          "coverage": ""
        },
        "22": {
          "source": "    \"type\": \"POST\",",
          "coverage": ""
        },
        "23": {
          "source": "    \"tryJSONP\": true,",
          "coverage": ""
        },
        "24": {
          "source": "    \"data\": JSON.stringify(data),",
          "coverage": ""
        },
        "25": {
          "source": "    \"dataType\": \"json\",",
          "coverage": ""
        },
        "26": {
          "source": "    \"contentType\": \"application/json\",",
          "coverage": ""
        },
        "27": {
          "source": "    \"timeout\": opts.timeout || app_props.timeout,",
          "coverage": ""
        },
        "28": {
          "source": "    \"headers\": fhparams.getFHHeaders(),",
          "coverage": ""
        },
        "29": {
          "source": "    success: function(res){",
          "coverage": ""
        },
        "30": {
          "source": "      if(success){",
          "coverage": ""
        },
        "31": {
          "source": "        return success(res);",
          "coverage": 0
        },
        "32": {
          "source": "      }",
          "coverage": ""
        },
        "33": {
          "source": "    },",
          "coverage": ""
        },
        "34": {
          "source": "    error: function(req, statusText, error){",
          "coverage": ""
        },
        "35": {
          "source": "      logger.error('got error when calling ' + endpoint, req.responseText || req, error);",
          "coverage": 0
        },
        "36": {
          "source": "      if(fail){",
          "coverage": ""
        },
        "37": {
          "source": "        fail(req, statusText, error);",
          "coverage": 0
        },
        "38": {
          "source": "      }",
          "coverage": ""
        },
        "39": {
          "source": "    }",
          "coverage": ""
        },
        "40": {
          "source": "  });",
          "coverage": ""
        },
        "41": {
          "source": "}",
          "coverage": ""
        },
        "42": {
          "source": "",
          "coverage": ""
        },
        "43": {
          "source": "var auth = function(opts, success, fail) {",
          "coverage": 1
        },
        "44": {
          "source": "  if (!fail) {",
          "coverage": ""
        },
        "45": {
          "source": "    fail = function(msg, error) {",
          "coverage": 0
        },
        "46": {
          "source": "      logger.debug(msg + \":\" + JSON.stringify(error));",
          "coverage": 0
        },
        "47": {
          "source": "    };",
          "coverage": ""
        },
        "48": {
          "source": "  }",
          "coverage": ""
        },
        "49": {
          "source": "  if (!opts.policyId) {",
          "coverage": ""
        },
        "50": {
          "source": "    return fail('auth_no_policyId', {});",
          "coverage": 0
        },
        "51": {
          "source": "  }",
          "coverage": ""
        },
        "52": {
          "source": "  if (!opts.clientToken) {",
          "coverage": ""
        },
        "53": {
          "source": "    return fail('auth_no_clientToken', {});",
          "coverage": 0
        },
        "54": {
          "source": "  }",
          "coverage": ""
        },
        "55": {
          "source": "",
          "coverage": ""
        },
        "56": {
          "source": "  cloud.ready(function(err, data) {",
          "coverage": 0
        },
        "57": {
          "source": "    if (err) {",
          "coverage": ""
        },
        "58": {
          "source": "      return fail(err.message, err);",
          "coverage": 0
        },
        "59": {
          "source": "    } else {",
          "coverage": ""
        },
        "60": {
          "source": "      var req = {};",
          "coverage": 0
        },
        "61": {
          "source": "      req.policyId = opts.policyId;",
          "coverage": 0
        },
        "62": {
          "source": "      req.clientToken = opts.clientToken;",
          "coverage": 0
        },
        "63": {
          "source": "      var cloudHost = cloud.getCloudHost();",
          "coverage": 0
        },
        "64": {
          "source": "      if(cloudHost.getEnv()){",
          "coverage": ""
        },
        "65": {
          "source": "        req.environment = cloudHost.getEnv(); ",
          "coverage": 0
        },
        "66": {
          "source": "      }",
          "coverage": ""
        },
        "67": {
          "source": "      if (opts.endRedirectUrl) {",
          "coverage": ""
        },
        "68": {
          "source": "        req.endRedirectUrl = opts.endRedirectUrl;",
          "coverage": 0
        },
        "69": {
          "source": "        if (opts.authCallback) {",
          "coverage": ""
        },
        "70": {
          "source": "          req.endRedirectUrl += (/\\?/.test(req.endRedirectUrl) ? \"&\" : \"?\") + \"_fhAuthCallback=\" + opts.authCallback;",
          "coverage": 0
        },
        "71": {
          "source": "        }",
          "coverage": ""
        },
        "72": {
          "source": "      }",
          "coverage": ""
        },
        "73": {
          "source": "      req.params = {};",
          "coverage": 0
        },
        "74": {
          "source": "      if (opts.params) {",
          "coverage": ""
        },
        "75": {
          "source": "        req.params = opts.params;",
          "coverage": 0
        },
        "76": {
          "source": "      }",
          "coverage": ""
        },
        "77": {
          "source": "      var endurl = opts.endRedirectUrl || \"status=complete\";",
          "coverage": 0
        },
        "78": {
          "source": "      req.device = device.getDeviceId();",
          "coverage": 0
        },
        "79": {
          "source": "      req = fhparams.addFHParams(req);",
          "coverage": 0
        },
        "80": {
          "source": "      callAuthEndpoint('auth', req, opts, function(res){",
          "coverage": 0
        },
        "81": {
          "source": "        auth.authenticateHandler(endurl, res, success, fail);",
          "coverage": 0
        },
        "82": {
          "source": "      }, function(req, statusText, error){",
          "coverage": ""
        },
        "83": {
          "source": "        handleError(fail, req, statusText, error);",
          "coverage": 0
        },
        "84": {
          "source": "      });",
          "coverage": ""
        },
        "85": {
          "source": "    }",
          "coverage": ""
        },
        "86": {
          "source": "  });",
          "coverage": ""
        },
        "87": {
          "source": "};",
          "coverage": ""
        },
        "88": {
          "source": "",
          "coverage": ""
        },
        "89": {
          "source": "auth.hasSession = function(cb){",
          "coverage": 1
        },
        "90": {
          "source": "  data.sessionManager.exists(cb);",
          "coverage": 0
        },
        "91": {
          "source": "};",
          "coverage": ""
        },
        "92": {
          "source": "",
          "coverage": ""
        },
        "93": {
          "source": "auth.clearSession = function(cb){",
          "coverage": 1
        },
        "94": {
          "source": "  data.sessionManager.read(function(err, session){",
          "coverage": 0
        },
        "95": {
          "source": "    if(err){",
          "coverage": ""
        },
        "96": {
          "source": "      return cb(err);",
          "coverage": 0
        },
        "97": {
          "source": "    }",
          "coverage": ""
        },
        "98": {
          "source": "    if(session){",
          "coverage": ""
        },
        "99": {
          "source": "      //try the best to delete the remote session",
          "coverage": ""
        },
        "100": {
          "source": "      callAuthEndpoint('revokesession', session, {});",
          "coverage": 0
        },
        "101": {
          "source": "    }",
          "coverage": ""
        },
        "102": {
          "source": "    data.sessionManager.remove(cb);",
          "coverage": 0
        },
        "103": {
          "source": "    fhparams.setAuthSessionToken(undefined);",
          "coverage": 0
        },
        "104": {
          "source": "  });",
          "coverage": ""
        },
        "105": {
          "source": "};",
          "coverage": ""
        },
        "106": {
          "source": "",
          "coverage": ""
        },
        "107": {
          "source": "auth.authenticateHandler = checkAuth.handleAuthResponse;",
          "coverage": 1
        },
        "108": {
          "source": "",
          "coverage": ""
        },
        "109": {
          "source": "auth.verify = function(cb){",
          "coverage": 1
        },
        "110": {
          "source": "  data.sessionManager.read(function(err, session){",
          "coverage": 0
        },
        "111": {
          "source": "    if(err){",
          "coverage": ""
        },
        "112": {
          "source": "      return cb(err);",
          "coverage": 0
        },
        "113": {
          "source": "    }",
          "coverage": ""
        },
        "114": {
          "source": "    if(session){",
          "coverage": ""
        },
        "115": {
          "source": "      //try the best to delete the session in remote",
          "coverage": ""
        },
        "116": {
          "source": "      callAuthEndpoint('verifysession', session, {}, function(res){",
          "coverage": 0
        },
        "117": {
          "source": "        return cb(null, res.isValid);",
          "coverage": 0
        },
        "118": {
          "source": "      }, function(req, statusText, error){",
          "coverage": ""
        },
        "119": {
          "source": "        return cb('network_error');",
          "coverage": 0
        },
        "120": {
          "source": "      });",
          "coverage": ""
        },
        "121": {
          "source": "    } else {",
          "coverage": ""
        },
        "122": {
          "source": "      return cb('no_session');",
          "coverage": 0
        },
        "123": {
          "source": "    }",
          "coverage": ""
        },
        "124": {
          "source": "  });",
          "coverage": ""
        },
        "125": {
          "source": "};",
          "coverage": ""
        },
        "126": {
          "source": "",
          "coverage": ""
        },
        "127": {
          "source": "module.exports = auth;",
          "coverage": 1
        }
      }
    },
    {
      "filename": "src/modules/api_cloud.js",
      "coverage": 30.76923076923077,
      "hits": 8,
      "misses": 18,
      "sloc": 26,
      "source": {
        "1": {
          "source": "var logger =require(\"./logger\");",
          "coverage": 1
        },
        "2": {
          "source": "var cloud = require(\"./waitForCloud\");",
          "coverage": 1
        },
        "3": {
          "source": "var fhparams = require(\"./fhparams\");",
          "coverage": 1
        },
        "4": {
          "source": "var ajax = require(\"./ajax\");",
          "coverage": 1
        },
        "5": {
          "source": "var handleError = require(\"./handleError\");",
          "coverage": 1
        },
        "6": {
          "source": "var appProps = require(\"./appProps\");",
          "coverage": 1
        },
        "7": {
          "source": "var _ = require('underscore');",
          "coverage": 1
        },
        "8": {
          "source": "",
          "coverage": ""
        },
        "9": {
          "source": "function doCloudCall(opts, success, fail){",
          "coverage": ""
        },
        "10": {
          "source": "  var cloud_host = cloud.getCloudHost();",
          "coverage": 0
        },
        "11": {
          "source": "  var url = cloud_host.getCloudUrl(opts.path);",
          "coverage": 0
        },
        "12": {
          "source": "  var params = opts.data || {};",
          "coverage": 0
        },
        "13": {
          "source": "  var type = opts.method || \"POST\";",
          "coverage": 0
        },
        "14": {
          "source": "  var data;",
          "coverage": 0
        },
        "15": {
          "source": "  if ([\"POST\", \"PUT\", \"PATCH\", \"DELETE\"].indexOf(type.toUpperCase()) !== -1) {",
          "coverage": ""
        },
        "16": {
          "source": "    data = JSON.stringify(params);",
          "coverage": 0
        },
        "17": {
          "source": "  } else {",
          "coverage": ""
        },
        "18": {
          "source": "    data = params;",
          "coverage": 0
        },
        "19": {
          "source": "  }",
          "coverage": ""
        },
        "20": {
          "source": "",
          "coverage": ""
        },
        "21": {
          "source": "  var headers = fhparams.getFHHeaders();",
          "coverage": 0
        },
        "22": {
          "source": "  if (opts.headers) {",
          "coverage": ""
        },
        "23": {
          "source": "    headers = _.extend(headers, opts.headers);",
          "coverage": 0
        },
        "24": {
          "source": "  }",
          "coverage": ""
        },
        "25": {
          "source": "",
          "coverage": ""
        },
        "26": {
          "source": "  return ajax({",
          "coverage": 0
        },
        "27": {
          "source": "    \"url\": url,",
          "coverage": ""
        },
        "28": {
          "source": "    \"type\": type,",
          "coverage": ""
        },
        "29": {
          "source": "    \"dataType\": opts.dataType || \"json\",",
          "coverage": ""
        },
        "30": {
          "source": "    \"data\": data,",
          "coverage": ""
        },
        "31": {
          "source": "    \"contentType\": opts.contentType || \"application/json\",",
          "coverage": ""
        },
        "32": {
          "source": "    \"timeout\": opts.timeout || appProps.timeout,",
          "coverage": ""
        },
        "33": {
          "source": "    \"headers\": headers,",
          "coverage": ""
        },
        "34": {
          "source": "    \"success\": success,",
          "coverage": ""
        },
        "35": {
          "source": "    \"error\": function(req, statusText, error){",
          "coverage": ""
        },
        "36": {
          "source": "      return handleError(fail, req, statusText, error);",
          "coverage": 0
        },
        "37": {
          "source": "    }",
          "coverage": ""
        },
        "38": {
          "source": "  });",
          "coverage": ""
        },
        "39": {
          "source": "}",
          "coverage": ""
        },
        "40": {
          "source": "",
          "coverage": ""
        },
        "41": {
          "source": "module.exports = function(opts, success, fail){",
          "coverage": 1
        },
        "42": {
          "source": "  logger.debug(\"cloud is called\");",
          "coverage": 0
        },
        "43": {
          "source": "  if(!fail){",
          "coverage": ""
        },
        "44": {
          "source": "    fail = function(msg, error){",
          "coverage": 0
        },
        "45": {
          "source": "      logger.debug(msg + \":\" + JSON.stringify(error));",
          "coverage": 0
        },
        "46": {
          "source": "    };",
          "coverage": ""
        },
        "47": {
          "source": "  }",
          "coverage": ""
        },
        "48": {
          "source": "",
          "coverage": ""
        },
        "49": {
          "source": "  cloud.ready(function(err, cloudHost){",
          "coverage": 0
        },
        "50": {
          "source": "    logger.debug(\"Calling fhact now\");",
          "coverage": 0
        },
        "51": {
          "source": "    if(err){",
          "coverage": ""
        },
        "52": {
          "source": "      return fail(err.message, err);",
          "coverage": 0
        },
        "53": {
          "source": "    } else {",
          "coverage": ""
        },
        "54": {
          "source": "      doCloudCall(opts, success, fail);",
          "coverage": 0
        },
        "55": {
          "source": "    }",
          "coverage": ""
        },
        "56": {
          "source": "  });",
          "coverage": ""
        },
        "57": {
          "source": "};",
          "coverage": ""
        },
        "58": {
          "source": "",
          "coverage": ""
        }
      }
    },
    {
      "filename": "src/modules/api_hash.js",
      "coverage": 28.57142857142857,
      "hits": 2,
      "misses": 5,
      "sloc": 7,
      "source": {
        "1": {
          "source": "var hashImpl = require(\"./security/hash\");",
          "coverage": 1
        },
        "2": {
          "source": "",
          "coverage": ""
        },
        "3": {
          "source": "module.exports = function(p, s, f){",
          "coverage": 1
        },
        "4": {
          "source": "  var params = {};",
          "coverage": 0
        },
        "5": {
          "source": "  if(typeof p.algorithm === \"undefined\"){",
          "coverage": ""
        },
        "6": {
          "source": "    p.algorithm = \"MD5\";",
          "coverage": 0
        },
        "7": {
          "source": "  }",
          "coverage": ""
        },
        "8": {
          "source": "  params.act = \"hash\";",
          "coverage": 0
        },
        "9": {
          "source": "  params.params = p;",
          "coverage": 0
        },
        "10": {
          "source": "  hashImpl(params, s, f);",
          "coverage": 0
        },
        "11": {
          "source": "};",
          "coverage": ""
        }
      }
    },
    {
      "filename": "src/modules/api_mbaas.js",
      "coverage": 38.095238095238095,
      "hits": 8,
      "misses": 13,
      "sloc": 21,
      "source": {
        "1": {
          "source": "var logger =require(\"./logger\");",
          "coverage": 1
        },
        "2": {
          "source": "var cloud = require(\"./waitForCloud\");",
          "coverage": 1
        },
        "3": {
          "source": "var fhparams = require(\"./fhparams\");",
          "coverage": 1
        },
        "4": {
          "source": "var ajax = require(\"./ajax\");",
          "coverage": 1
        },
        "5": {
          "source": "var handleError = require(\"./handleError\");",
          "coverage": 1
        },
        "6": {
          "source": "var consts = require(\"./constants\");",
          "coverage": 1
        },
        "7": {
          "source": "var appProps = require(\"./appProps\");",
          "coverage": 1
        },
        "8": {
          "source": "",
          "coverage": ""
        },
        "9": {
          "source": "module.exports = function(opts, success, fail){",
          "coverage": 1
        },
        "10": {
          "source": "  logger.debug(\"mbaas is called.\");",
          "coverage": 0
        },
        "11": {
          "source": "  if(!fail){",
          "coverage": ""
        },
        "12": {
          "source": "    fail = function(msg, error){",
          "coverage": 0
        },
        "13": {
          "source": "      console.debug(msg + \":\" + JSON.stringify(error));",
          "coverage": 0
        },
        "14": {
          "source": "    };",
          "coverage": ""
        },
        "15": {
          "source": "  }",
          "coverage": ""
        },
        "16": {
          "source": "",
          "coverage": ""
        },
        "17": {
          "source": "  var mbaas = opts.service;",
          "coverage": 0
        },
        "18": {
          "source": "  var params = opts.params;",
          "coverage": 0
        },
        "19": {
          "source": "",
          "coverage": ""
        },
        "20": {
          "source": "  cloud.ready(function(err, cloudHost){",
          "coverage": 0
        },
        "21": {
          "source": "    logger.debug(\"Calling mbaas now\");",
          "coverage": 0
        },
        "22": {
          "source": "    if(err){",
          "coverage": ""
        },
        "23": {
          "source": "      return fail(err.message, err);",
          "coverage": 0
        },
        "24": {
          "source": "    } else {",
          "coverage": ""
        },
        "25": {
          "source": "      var cloud_host = cloud.getCloudHost();",
          "coverage": 0
        },
        "26": {
          "source": "      var url = cloud_host.getMBAASUrl(mbaas);",
          "coverage": 0
        },
        "27": {
          "source": "      params = fhparams.addFHParams(params);",
          "coverage": 0
        },
        "28": {
          "source": "      return ajax({",
          "coverage": 0
        },
        "29": {
          "source": "        \"url\": url,",
          "coverage": ""
        },
        "30": {
          "source": "        \"tryJSONP\": true,",
          "coverage": ""
        },
        "31": {
          "source": "        \"type\": \"POST\",",
          "coverage": ""
        },
        "32": {
          "source": "        \"dataType\": \"json\",",
          "coverage": ""
        },
        "33": {
          "source": "        \"data\": JSON.stringify(params),",
          "coverage": ""
        },
        "34": {
          "source": "        \"headers\": fhparams.getFHHeaders(),",
          "coverage": ""
        },
        "35": {
          "source": "        \"contentType\": \"application/json\",",
          "coverage": ""
        },
        "36": {
          "source": "        \"timeout\": opts.timeout || appProps.timeout,",
          "coverage": ""
        },
        "37": {
          "source": "        \"success\": success,",
          "coverage": ""
        },
        "38": {
          "source": "        \"error\": function(req, statusText, error){",
          "coverage": ""
        },
        "39": {
          "source": "          return handleError(fail, req, statusText, error);",
          "coverage": 0
        },
        "40": {
          "source": "        }",
          "coverage": ""
        },
        "41": {
          "source": "      });",
          "coverage": ""
        },
        "42": {
          "source": "    }",
          "coverage": ""
        },
        "43": {
          "source": "  });",
          "coverage": ""
        },
        "44": {
          "source": "};",
          "coverage": ""
        }
      }
    },
    {
      "filename": "src/modules/api_push.js",
      "coverage": 28.57142857142857,
      "hits": 4,
      "misses": 10,
      "sloc": 14,
      "source": {
        "1": {
          "source": "var logger = require(\"./logger\");",
          "coverage": 1
        },
        "2": {
          "source": "var appProps = require(\"./appProps\");",
          "coverage": 1
        },
        "3": {
          "source": "var cloud = require(\"./waitForCloud\");",
          "coverage": 1
        },
        "4": {
          "source": "",
          "coverage": ""
        },
        "5": {
          "source": "module.exports = function (onNotification, success, fail, config) {",
          "coverage": 1
        },
        "6": {
          "source": "  if (!fail) {",
          "coverage": ""
        },
        "7": {
          "source": "    fail = function (msg, error) {",
          "coverage": 0
        },
        "8": {
          "source": "      logger.debug(msg + \":\" + JSON.stringify(error));",
          "coverage": 0
        },
        "9": {
          "source": "    };",
          "coverage": ""
        },
        "10": {
          "source": "  }",
          "coverage": ""
        },
        "11": {
          "source": "",
          "coverage": ""
        },
        "12": {
          "source": "  cloud.ready(function(err, cloudHost){",
          "coverage": 0
        },
        "13": {
          "source": "    logger.debug(\"push is called\");",
          "coverage": 0
        },
        "14": {
          "source": "    if(err){",
          "coverage": ""
        },
        "15": {
          "source": "      return fail(err.message, err);",
          "coverage": 0
        },
        "16": {
          "source": "    } else {",
          "coverage": ""
        },
        "17": {
          "source": "      if (window.push) {",
          "coverage": ""
        },
        "18": {
          "source": "        var props = appProps.getAppProps();",
          "coverage": 0
        },
        "19": {
          "source": "        props.pushServerURL = props.host + '/api/v2/ag-push';",
          "coverage": 0
        },
        "20": {
          "source": "        if (config) {",
          "coverage": ""
        },
        "21": {
          "source": "          for(var key in config) {",
          "coverage": ""
        },
        "22": {
          "source": "            props[key] = config[key];",
          "coverage": 0
        },
        "23": {
          "source": "          }",
          "coverage": ""
        },
        "24": {
          "source": "        }",
          "coverage": ""
        },
        "25": {
          "source": "        window.push.register(onNotification, success, fail, props);",
          "coverage": 0
        },
        "26": {
          "source": "      } else {",
          "coverage": ""
        },
        "27": {
          "source": "        fail('push plugin not installed');",
          "coverage": 0
        },
        "28": {
          "source": "      }",
          "coverage": ""
        },
        "29": {
          "source": "    }",
          "coverage": ""
        },
        "30": {
          "source": "  });",
          "coverage": ""
        },
        "31": {
          "source": "};",
          "coverage": ""
        },
        "32": {
          "source": "",
          "coverage": ""
        }
      }
    },
    {
      "filename": "src/modules/api_sec.js",
      "coverage": 25,
      "hits": 5,
      "misses": 15,
      "sloc": 20,
      "source": {
        "1": {
          "source": "var keygen = require(\"./security/aes-keygen\");",
          "coverage": 1
        },
        "2": {
          "source": "var aes = require(\"./security/aes-node\");",
          "coverage": 1
        },
        "3": {
          "source": "var rsa = require(\"./security/rsa-node\");",
          "coverage": 1
        },
        "4": {
          "source": "var hash = require(\"./security/hash\");",
          "coverage": 1
        },
        "5": {
          "source": "",
          "coverage": ""
        },
        "6": {
          "source": "module.exports = function(p, s, f){",
          "coverage": 1
        },
        "7": {
          "source": "  if (!p.act) {",
          "coverage": ""
        },
        "8": {
          "source": "    f('bad_act', {}, p);",
          "coverage": 0
        },
        "9": {
          "source": "    return;",
          "coverage": 0
        },
        "10": {
          "source": "  }",
          "coverage": ""
        },
        "11": {
          "source": "  if (!p.params) {",
          "coverage": ""
        },
        "12": {
          "source": "    f('no_params', {}, p);",
          "coverage": 0
        },
        "13": {
          "source": "    return;",
          "coverage": 0
        },
        "14": {
          "source": "  }",
          "coverage": ""
        },
        "15": {
          "source": "  if (!p.params.algorithm) {",
          "coverage": ""
        },
        "16": {
          "source": "    f('no_params_algorithm', {}, p);",
          "coverage": 0
        },
        "17": {
          "source": "    return;",
          "coverage": 0
        },
        "18": {
          "source": "  }",
          "coverage": ""
        },
        "19": {
          "source": "  p.params.algorithm = p.params.algorithm.toLowerCase();",
          "coverage": 0
        },
        "20": {
          "source": "  if(p.act === \"hash\"){",
          "coverage": ""
        },
        "21": {
          "source": "    return hash(p, s, f);",
          "coverage": 0
        },
        "22": {
          "source": "  } else if(p.act === \"encrypt\"){",
          "coverage": ""
        },
        "23": {
          "source": "    if(p.params.algorithm === \"aes\"){",
          "coverage": ""
        },
        "24": {
          "source": "      return aes.encrypt(p, s, f);",
          "coverage": 0
        },
        "25": {
          "source": "    } else if(p.params.algorithm === \"rsa\"){",
          "coverage": ""
        },
        "26": {
          "source": "      return rsa.encrypt(p, s, f);",
          "coverage": 0
        },
        "27": {
          "source": "    } else {",
          "coverage": ""
        },
        "28": {
          "source": "      return f('encrypt_bad_algorithm:' + p.params.algorithm, {}, p);",
          "coverage": 0
        },
        "29": {
          "source": "    }",
          "coverage": ""
        },
        "30": {
          "source": "  } else if(p.act === \"decrypt\"){",
          "coverage": ""
        },
        "31": {
          "source": "    if(p.params.algorithm === \"aes\"){",
          "coverage": ""
        },
        "32": {
          "source": "      return aes.decrypt(p, s, f);",
          "coverage": 0
        },
        "33": {
          "source": "    } else {",
          "coverage": ""
        },
        "34": {
          "source": "      return f('decrypt_bad_algorithm:' + p.params.algorithm, {}, p);",
          "coverage": 0
        },
        "35": {
          "source": "    }",
          "coverage": ""
        },
        "36": {
          "source": "  } else if(p.act === \"keygen\"){",
          "coverage": ""
        },
        "37": {
          "source": "    if(p.params.algorithm === \"aes\"){",
          "coverage": ""
        },
        "38": {
          "source": "      return keygen(p, s, f);",
          "coverage": 0
        },
        "39": {
          "source": "    } else {",
          "coverage": ""
        },
        "40": {
          "source": "      return f('keygen_bad_algorithm:' + p.params.algorithm, {}, p);",
          "coverage": 0
        },
        "41": {
          "source": "    }",
          "coverage": ""
        },
        "42": {
          "source": "  }",
          "coverage": ""
        },
        "43": {
          "source": "};",
          "coverage": ""
        }
      }
    },
    {
      "filename": "src/modules/appProps.js",
      "coverage": 76.66666666666667,
      "hits": 23,
      "misses": 7,
      "sloc": 30,
      "source": {
        "1": {
          "source": "var consts = require(\"./constants\");",
          "coverage": 1
        },
        "2": {
          "source": "var ajax = require(\"./ajax\");",
          "coverage": 1
        },
        "3": {
          "source": "var logger = require(\"./logger\");",
          "coverage": 1
        },
        "4": {
          "source": "var qs = require(\"./queryMap\");",
          "coverage": 1
        },
        "5": {
          "source": "var _ = require('underscore');",
          "coverage": 1
        },
        "6": {
          "source": "",
          "coverage": ""
        },
        "7": {
          "source": "var app_props = null;",
          "coverage": 1
        },
        "8": {
          "source": "",
          "coverage": ""
        },
        "9": {
          "source": "var load = function(cb) {",
          "coverage": 1
        },
        "10": {
          "source": "  var doc_url = document.location.href;",
          "coverage": 1
        },
        "11": {
          "source": "  var url_params = qs(doc_url.replace(/#.*?$/g, ''));",
          "coverage": 1
        },
        "12": {
          "source": "  var url_props = {};",
          "coverage": 1
        },
        "13": {
          "source": "  ",
          "coverage": ""
        },
        "14": {
          "source": "  //only use fh_ prefixed params",
          "coverage": ""
        },
        "15": {
          "source": "  for(var key in url_params){",
          "coverage": ""
        },
        "16": {
          "source": "    if(url_params.hasOwnProperty(key) ){",
          "coverage": ""
        },
        "17": {
          "source": "      if(key.indexOf('fh_') === 0){",
          "coverage": ""
        },
        "18": {
          "source": "        url_props[key.substr(3)] = decodeURI(url_params[key]); ",
          "coverage": 0
        },
        "19": {
          "source": "      }",
          "coverage": ""
        },
        "20": {
          "source": "    }",
          "coverage": ""
        },
        "21": {
          "source": "  }",
          "coverage": ""
        },
        "22": {
          "source": "  ",
          "coverage": ""
        },
        "23": {
          "source": "  //default properties",
          "coverage": ""
        },
        "24": {
          "source": "  app_props = {",
          "coverage": 1
        },
        "25": {
          "source": "    appid: \"000000000000000000000000\",",
          "coverage": ""
        },
        "26": {
          "source": "    appkey: \"0000000000000000000000000000000000000000\",",
          "coverage": ""
        },
        "27": {
          "source": "    projectid: \"000000000000000000000000\",",
          "coverage": ""
        },
        "28": {
          "source": "    connectiontag: \"0.0.1\"",
          "coverage": ""
        },
        "29": {
          "source": "  };",
          "coverage": ""
        },
        "30": {
          "source": "  ",
          "coverage": ""
        },
        "31": {
          "source": "  function setProps(props){",
          "coverage": ""
        },
        "32": {
          "source": "    _.extend(app_props, props, url_props);",
          "coverage": 1
        },
        "33": {
          "source": "    ",
          "coverage": ""
        },
        "34": {
          "source": "    if(typeof url_params.url !== 'undefined'){",
          "coverage": ""
        },
        "35": {
          "source": "     app_props.host = url_params.url; ",
          "coverage": 1
        },
        "36": {
          "source": "    }",
          "coverage": ""
        },
        "37": {
          "source": "    ",
          "coverage": ""
        },
        "38": {
          "source": "    app_props.local = !!(url_props.host || url_params.url || (props.local && props.host));",
          "coverage": 1
        },
        "39": {
          "source": "    cb(null, app_props);",
          "coverage": 1
        },
        "40": {
          "source": "  }",
          "coverage": ""
        },
        "41": {
          "source": "",
          "coverage": ""
        },
        "42": {
          "source": "  var config_url = url_params.fhconfig || consts.config_js;",
          "coverage": 1
        },
        "43": {
          "source": "  ajax({",
          "coverage": 1
        },
        "44": {
          "source": "    url: config_url,",
          "coverage": ""
        },
        "45": {
          "source": "    dataType: \"json\",",
          "coverage": ""
        },
        "46": {
          "source": "    success: function(data) {",
          "coverage": ""
        },
        "47": {
          "source": "      logger.debug(\"fhconfig = \" + JSON.stringify(data));",
          "coverage": 1
        },
        "48": {
          "source": "      //when load the config file on device, because file:// protocol is used, it will never call fail call back. The success callback will be called but the data value will be null.",
          "coverage": ""
        },
        "49": {
          "source": "      if (null == data) {",
          "coverage": ""
        },
        "50": {
          "source": "        //fh v2 only",
          "coverage": ""
        },
        "51": {
          "source": "        if(window.fh_app_props){",
          "coverage": ""
        },
        "52": {
          "source": "          return setProps(window.fh_app_props);",
          "coverage": 0
        },
        "53": {
          "source": "        }",
          "coverage": ""
        },
        "54": {
          "source": "        return cb(new Error(\"app_config_missing\"));",
          "coverage": 0
        },
        "55": {
          "source": "      } else {",
          "coverage": ""
        },
        "56": {
          "source": "",
          "coverage": ""
        },
        "57": {
          "source": "        setProps(data);",
          "coverage": 1
        },
        "58": {
          "source": "      }",
          "coverage": ""
        },
        "59": {
          "source": "    },",
          "coverage": ""
        },
        "60": {
          "source": "    error: function(req, statusText, error) {",
          "coverage": ""
        },
        "61": {
          "source": "      //fh v2 only",
          "coverage": ""
        },
        "62": {
          "source": "      if(window.fh_app_props){",
          "coverage": ""
        },
        "63": {
          "source": "        return setProps(window.fh_app_props);",
          "coverage": 0
        },
        "64": {
          "source": "      }",
          "coverage": ""
        },
        "65": {
          "source": "      logger.error(consts.config_js + \" Not Found\");",
          "coverage": 0
        },
        "66": {
          "source": "      cb(new Error(\"app_config_missing\"));",
          "coverage": 0
        },
        "67": {
          "source": "    }",
          "coverage": ""
        },
        "68": {
          "source": "  });",
          "coverage": ""
        },
        "69": {
          "source": "};",
          "coverage": ""
        },
        "70": {
          "source": "",
          "coverage": ""
        },
        "71": {
          "source": "var setAppProps = function(props) {",
          "coverage": 1
        },
        "72": {
          "source": "  app_props = props;",
          "coverage": 0
        },
        "73": {
          "source": "};",
          "coverage": ""
        },
        "74": {
          "source": "",
          "coverage": ""
        },
        "75": {
          "source": "var getAppProps = function() {",
          "coverage": 1
        },
        "76": {
          "source": "  return app_props;",
          "coverage": 3
        },
        "77": {
          "source": "};",
          "coverage": ""
        },
        "78": {
          "source": "",
          "coverage": ""
        },
        "79": {
          "source": "module.exports = {",
          "coverage": 1
        },
        "80": {
          "source": "  load: load,",
          "coverage": ""
        },
        "81": {
          "source": "  getAppProps: getAppProps,",
          "coverage": ""
        },
        "82": {
          "source": "  setAppProps: setAppProps",
          "coverage": ""
        },
        "83": {
          "source": "};",
          "coverage": ""
        },
        "84": {
          "source": "",
          "coverage": ""
        }
      }
    },
    {
      "filename": "src/modules/checkAuth.js",
      "coverage": 21.428571428571427,
      "hits": 9,
      "misses": 33,
      "sloc": 42,
      "source": {
        "1": {
          "source": "var logger = require(\"./logger\");",
          "coverage": 1
        },
        "2": {
          "source": "var queryMap = require(\"./queryMap\");",
          "coverage": 1
        },
        "3": {
          "source": "var fhparams = require(\"./fhparams\");",
          "coverage": 1
        },
        "4": {
          "source": "var data = require('./data');",
          "coverage": 1
        },
        "5": {
          "source": "",
          "coverage": ""
        },
        "6": {
          "source": "var checkAuth = function(url) {",
          "coverage": 1
        },
        "7": {
          "source": "  if (/\\_fhAuthCallback/.test(url)) {",
          "coverage": ""
        },
        "8": {
          "source": "    var qmap = queryMap(url);",
          "coverage": 0
        },
        "9": {
          "source": "    if (qmap) {",
          "coverage": ""
        },
        "10": {
          "source": "      var fhCallback = qmap[\"_fhAuthCallback\"];",
          "coverage": 0
        },
        "11": {
          "source": "      if (fhCallback) {",
          "coverage": ""
        },
        "12": {
          "source": "        if (qmap['result'] && qmap['result'] === 'success') {",
          "coverage": ""
        },
        "13": {
          "source": "          var sucRes = {'sessionToken': qmap['fh_auth_session'], 'authResponse' : JSON.parse(decodeURIComponent(decodeURIComponent(qmap['authResponse'])))};",
          "coverage": 0
        },
        "14": {
          "source": "          fhparams.setAuthSessionToken(qmap['fh_auth_session']);",
          "coverage": 0
        },
        "15": {
          "source": "          data.sessionManager.save(qmap['fh_auth_session']);",
          "coverage": 0
        },
        "16": {
          "source": "          window[fhCallback](null, sucRes);",
          "coverage": 0
        },
        "17": {
          "source": "        } else {",
          "coverage": ""
        },
        "18": {
          "source": "          window[fhCallback]({'message':qmap['message']});",
          "coverage": 0
        },
        "19": {
          "source": "        }",
          "coverage": ""
        },
        "20": {
          "source": "      }",
          "coverage": ""
        },
        "21": {
          "source": "    }",
          "coverage": ""
        },
        "22": {
          "source": "  }",
          "coverage": ""
        },
        "23": {
          "source": "};",
          "coverage": ""
        },
        "24": {
          "source": "",
          "coverage": ""
        },
        "25": {
          "source": "var handleAuthResponse = function(endurl, res, success, fail){",
          "coverage": 1
        },
        "26": {
          "source": "  if(res.status && res.status === \"ok\"){",
          "coverage": ""
        },
        "27": {
          "source": "",
          "coverage": ""
        },
        "28": {
          "source": "    var onComplete = function(res){",
          "coverage": 0
        },
        "29": {
          "source": "      if(res.sessionToken){",
          "coverage": ""
        },
        "30": {
          "source": "        fhparams.setAuthSessionToken(res.sessionToken);",
          "coverage": 0
        },
        "31": {
          "source": "        data.sessionManager.save(res.sessionToken, function(){",
          "coverage": 0
        },
        "32": {
          "source": "          return success(res);",
          "coverage": 0
        },
        "33": {
          "source": "        });",
          "coverage": ""
        },
        "34": {
          "source": "      } else {",
          "coverage": ""
        },
        "35": {
          "source": "        return success(res);",
          "coverage": 0
        },
        "36": {
          "source": "      }",
          "coverage": ""
        },
        "37": {
          "source": "    };",
          "coverage": ""
        },
        "38": {
          "source": "    //for OAuth, a url will be returned which means the user should be directed to that url to authenticate.",
          "coverage": ""
        },
        "39": {
          "source": "    //we try to use the ChildBrower plugin if it can be found. Otherwise send the url to the success function to allow developer to handle it.",
          "coverage": ""
        },
        "40": {
          "source": "    if(res.url){",
          "coverage": ""
        },
        "41": {
          "source": "      var inappBrowserWindow = null;",
          "coverage": 0
        },
        "42": {
          "source": "      var locationChange = function(new_url){",
          "coverage": 0
        },
        "43": {
          "source": "        if(new_url.indexOf(endurl) > -1){",
          "coverage": ""
        },
        "44": {
          "source": "          if(inappBrowserWindow){",
          "coverage": ""
        },
        "45": {
          "source": "            inappBrowserWindow.close();",
          "coverage": 0
        },
        "46": {
          "source": "          }",
          "coverage": ""
        },
        "47": {
          "source": "          var qmap = queryMap(new_url);",
          "coverage": 0
        },
        "48": {
          "source": "          if(qmap) {",
          "coverage": ""
        },
        "49": {
          "source": "            if(qmap['result'] && qmap['result'] === 'success'){",
          "coverage": ""
        },
        "50": {
          "source": "              var sucRes = {'sessionToken': qmap['fh_auth_session'], 'authResponse' : JSON.parse(decodeURIComponent(decodeURIComponent(qmap['authResponse'])))};",
          "coverage": 0
        },
        "51": {
          "source": "              onComplete(sucRes);",
          "coverage": 0
        },
        "52": {
          "source": "            } else {",
          "coverage": ""
        },
        "53": {
          "source": "              if(fail){",
          "coverage": ""
        },
        "54": {
          "source": "                fail(\"auth_failed\", {'message':qmap['message']});",
          "coverage": 0
        },
        "55": {
          "source": "              }",
          "coverage": ""
        },
        "56": {
          "source": "            }",
          "coverage": ""
        },
        "57": {
          "source": "          } else {",
          "coverage": ""
        },
        "58": {
          "source": "            if(fail){",
          "coverage": ""
        },
        "59": {
          "source": "                fail(\"auth_failed\", {'message':qmap['message']});",
          "coverage": 0
        },
        "60": {
          "source": "            }",
          "coverage": ""
        },
        "61": {
          "source": "          }",
          "coverage": ""
        },
        "62": {
          "source": "        }",
          "coverage": ""
        },
        "63": {
          "source": "      };",
          "coverage": ""
        },
        "64": {
          "source": "      if(window.PhoneGap || window.cordova){",
          "coverage": ""
        },
        "65": {
          "source": "        if(window.plugins && window.plugins.childBrowser){",
          "coverage": ""
        },
        "66": {
          "source": "          //found childbrowser plugin,add the event listener and load it",
          "coverage": ""
        },
        "67": {
          "source": "          //we need to know when the OAuth process is finished by checking for the presence of endurl. If the endurl is found, it means the authentication finished and we should find if it's successful.",
          "coverage": ""
        },
        "68": {
          "source": "          if(typeof window.plugins.childBrowser.showWebPage === \"function\"){",
          "coverage": ""
        },
        "69": {
          "source": "            window.plugins.childBrowser.onLocationChange = locationChange;",
          "coverage": 0
        },
        "70": {
          "source": "            window.plugins.childBrowser.showWebPage(res.url);",
          "coverage": 0
        },
        "71": {
          "source": "            inappBrowserWindow = window.plugins.childBrowser;",
          "coverage": 0
        },
        "72": {
          "source": "          }",
          "coverage": ""
        },
        "73": {
          "source": "        } else {",
          "coverage": ""
        },
        "74": {
          "source": "          try {",
          "coverage": ""
        },
        "75": {
          "source": "            inappBrowserWindow = window.open(res.url, \"_blank\", 'location=yes');",
          "coverage": 0
        },
        "76": {
          "source": "            inappBrowserWindow.addEventListener(\"loadstart\", function(ev){",
          "coverage": 0
        },
        "77": {
          "source": "              locationChange(ev.url);",
          "coverage": 0
        },
        "78": {
          "source": "            });",
          "coverage": ""
        },
        "79": {
          "source": "          } catch(e){",
          "coverage": ""
        },
        "80": {
          "source": "            logger.info(\"InAppBrowser plugin is not intalled.\");",
          "coverage": 0
        },
        "81": {
          "source": "            onComplete(res);",
          "coverage": 0
        },
        "82": {
          "source": "          }",
          "coverage": ""
        },
        "83": {
          "source": "        }",
          "coverage": ""
        },
        "84": {
          "source": "      } else {",
          "coverage": ""
        },
        "85": {
          "source": "       document.location.href = res.url;",
          "coverage": 0
        },
        "86": {
          "source": "      }",
          "coverage": ""
        },
        "87": {
          "source": "    } else {",
          "coverage": ""
        },
        "88": {
          "source": "      onComplete(res);",
          "coverage": 0
        },
        "89": {
          "source": "    }",
          "coverage": ""
        },
        "90": {
          "source": "  } else {",
          "coverage": ""
        },
        "91": {
          "source": "    if(fail){",
          "coverage": ""
        },
        "92": {
          "source": "      fail(\"auth_failed\", res);",
          "coverage": 0
        },
        "93": {
          "source": "    }",
          "coverage": ""
        },
        "94": {
          "source": "  }",
          "coverage": ""
        },
        "95": {
          "source": "};",
          "coverage": ""
        },
        "96": {
          "source": "",
          "coverage": ""
        },
        "97": {
          "source": "//This is mainly for using $fh.auth inside browsers. If the authentication method is OAuth, at the end of the process, the user will be re-directed to",
          "coverage": ""
        },
        "98": {
          "source": "//a url that we specified for checking if the auth is successful. So we always check the url to see if we are on the re-directed page.",
          "coverage": ""
        },
        "99": {
          "source": "if (window.addEventListener) {",
          "coverage": ""
        },
        "100": {
          "source": "  window.addEventListener('load', function(){",
          "coverage": 1
        },
        "101": {
          "source": "    checkAuth(window.location.href);",
          "coverage": 1
        },
        "102": {
          "source": "  }, false); //W3C",
          "coverage": ""
        },
        "103": {
          "source": "} else if (window.attachEvent) {",
          "coverage": ""
        },
        "104": {
          "source": "  window.attachEvent('onload', function(){",
          "coverage": 0
        },
        "105": {
          "source": "    checkAuth(window.location.href);",
          "coverage": 0
        },
        "106": {
          "source": "  }); //IE",
          "coverage": ""
        },
        "107": {
          "source": "}",
          "coverage": ""
        },
        "108": {
          "source": "",
          "coverage": ""
        },
        "109": {
          "source": "module.exports = {",
          "coverage": 1
        },
        "110": {
          "source": "  \"handleAuthResponse\": handleAuthResponse",
          "coverage": ""
        },
        "111": {
          "source": "};",
          "coverage": ""
        },
        "112": {
          "source": "",
          "coverage": ""
        }
      }
    },
    {
      "filename": "src/modules/constants.js",
      "coverage": 100,
      "hits": 1,
      "misses": 0,
      "sloc": 1,
      "source": {
        "1": {
          "source": "module.exports = {",
          "coverage": 1
        },
        "2": {
          "source": "  \"boxprefix\": \"/box/srv/1.1/\",",
          "coverage": ""
        },
        "3": {
          "source": "  \"sdk_version\": \"BUILD_VERSION\",",
          "coverage": ""
        },
        "4": {
          "source": "  \"config_js\": \"fhconfig.json\",",
          "coverage": ""
        },
        "5": {
          "source": "  \"INIT_EVENT\": \"fhinit\",",
          "coverage": ""
        },
        "6": {
          "source": "  \"INTERNAL_CONFIG_LOADED_EVENT\": \"internalfhconfigloaded\",",
          "coverage": ""
        },
        "7": {
          "source": "  \"CONFIG_LOADED_EVENT\": \"fhconfigloaded\",",
          "coverage": ""
        },
        "8": {
          "source": "  \"SESSION_TOKEN_STORAGE_NAME\": \"fh_session_token\",",
          "coverage": ""
        },
        "9": {
          "source": "  \"SESSION_TOKEN_KEY_NAME\":\"sessionToken\"",
          "coverage": ""
        },
        "10": {
          "source": "};",
          "coverage": ""
        },
        "11": {
          "source": "",
          "coverage": ""
        }
      }
    },
    {
      "filename": "src/modules/cookies.js",
      "coverage": 9.090909090909092,
      "hits": 1,
      "misses": 10,
      "sloc": 11,
      "source": {
        "1": {
          "source": "module.exports = {",
          "coverage": 1
        },
        "2": {
          "source": "  readCookieValue  : function (cookie_name) {",
          "coverage": ""
        },
        "3": {
          "source": "    var name_str = cookie_name + \"=\";",
          "coverage": 0
        },
        "4": {
          "source": "    var cookies = document.cookie.split(\";\");",
          "coverage": 0
        },
        "5": {
          "source": "    for (var i = 0; i < cookies.length; i++) {",
          "coverage": ""
        },
        "6": {
          "source": "      var c = cookies[i];",
          "coverage": 0
        },
        "7": {
          "source": "      while (c.charAt(0) === ' ') {",
          "coverage": ""
        },
        "8": {
          "source": "        c = c.substring(1, c.length);",
          "coverage": 0
        },
        "9": {
          "source": "      }",
          "coverage": ""
        },
        "10": {
          "source": "      if (c.indexOf(name_str) === 0) {",
          "coverage": ""
        },
        "11": {
          "source": "        return c.substring(name_str.length, c.length);",
          "coverage": 0
        },
        "12": {
          "source": "      }",
          "coverage": ""
        },
        "13": {
          "source": "    }",
          "coverage": ""
        },
        "14": {
          "source": "    return null;",
          "coverage": 0
        },
        "15": {
          "source": "  },",
          "coverage": ""
        },
        "16": {
          "source": "",
          "coverage": ""
        },
        "17": {
          "source": "  createCookie : function (cookie_name, cookie_value) {",
          "coverage": ""
        },
        "18": {
          "source": "    var date = new Date();",
          "coverage": 0
        },
        "19": {
          "source": "    date.setTime(date.getTime() + 36500 * 24 * 60 * 60 * 1000); //100 years",
          "coverage": 0
        },
        "20": {
          "source": "    var expires = \"; expires=\" + date.toGMTString();",
          "coverage": 0
        },
        "21": {
          "source": "    document.cookie = cookie_name + \"=\" + cookie_value + expires + \"; path = /\";",
          "coverage": 0
        },
        "22": {
          "source": "  }",
          "coverage": ""
        },
        "23": {
          "source": "};",
          "coverage": ""
        },
        "24": {
          "source": "",
          "coverage": ""
        }
      }
    },
    {
      "filename": "src/modules/data.js",
      "coverage": 54.166666666666664,
      "hits": 13,
      "misses": 11,
      "sloc": 24,
      "source": {
        "1": {
          "source": "var Lawnchair = require('../../libs/generated/lawnchair');",
          "coverage": 1
        },
        "2": {
          "source": "var lawnchairext = require('./lawnchair-ext');",
          "coverage": 1
        },
        "3": {
          "source": "var logger = require('./logger');",
          "coverage": 1
        },
        "4": {
          "source": "var constants = require(\"./constants\");",
          "coverage": 1
        },
        "5": {
          "source": "",
          "coverage": ""
        },
        "6": {
          "source": "var data = {",
          "coverage": 1
        },
        "7": {
          "source": "  //dom adapter doens't work on windows phone, so don't specify the adapter if the dom one failed",
          "coverage": ""
        },
        "8": {
          "source": "  //we specify the order of lawnchair adapters to use, lawnchair will find the right one to use, to keep backward compatibility, keep the order",
          "coverage": ""
        },
        "9": {
          "source": "  //as dom, webkit-sqlite, localFileStorage, window-name",
          "coverage": ""
        },
        "10": {
          "source": "  DEFAULT_ADAPTERS : [\"dom\", \"webkit-sqlite\", \"window-name\", \"titanium\"],",
          "coverage": ""
        },
        "11": {
          "source": "  getStorage: function(name, adapters, fail){",
          "coverage": ""
        },
        "12": {
          "source": "    var adpts = data.DEFAULT_ADAPTERS;",
          "coverage": 1
        },
        "13": {
          "source": "    var errorHandler = fail || function(){};",
          "coverage": 1
        },
        "14": {
          "source": "    if(adapters && adapters.length > 0){",
          "coverage": ""
        },
        "15": {
          "source": "      adpts = (typeof adapters === 'string'?[adapters]: adapters);",
          "coverage": 0
        },
        "16": {
          "source": "    }",
          "coverage": ""
        },
        "17": {
          "source": "    var conf = {",
          "coverage": 1
        },
        "18": {
          "source": "      name: name,",
          "coverage": ""
        },
        "19": {
          "source": "      adapter: adpts,",
          "coverage": ""
        },
        "20": {
          "source": "      fail: function(msg, err){",
          "coverage": ""
        },
        "21": {
          "source": "        var error_message = 'read/save from/to local storage failed  msg:' + msg + ' err:' + err;",
          "coverage": 0
        },
        "22": {
          "source": "        logger.error(error_message, err);",
          "coverage": 0
        },
        "23": {
          "source": "        errorHandler(error_message, {});",
          "coverage": 0
        },
        "24": {
          "source": "      }",
          "coverage": ""
        },
        "25": {
          "source": "    };",
          "coverage": ""
        },
        "26": {
          "source": "    var store = Lawnchair(conf, function(){});",
          "coverage": 1
        },
        "27": {
          "source": "    return store;",
          "coverage": 1
        },
        "28": {
          "source": "  },",
          "coverage": ""
        },
        "29": {
          "source": "  addFileStorageAdapter: function(appProps, hashFunc){",
          "coverage": ""
        },
        "30": {
          "source": "    Lawnchair.adapter('localFileStorage', lawnchairext.fileStorageAdapter(appProps, hashFunc));",
          "coverage": 0
        },
        "31": {
          "source": "  },",
          "coverage": ""
        },
        "32": {
          "source": "  sessionManager: {",
          "coverage": ""
        },
        "33": {
          "source": "    read: function(cb){",
          "coverage": ""
        },
        "34": {
          "source": "      data.getStorage(constants.SESSION_TOKEN_STORAGE_NAME).get(constants.SESSION_TOKEN_KEY_NAME, function(session){",
          "coverage": 1
        },
        "35": {
          "source": "        if(cb){",
          "coverage": ""
        },
        "36": {
          "source": "          return cb(null, session);",
          "coverage": 1
        },
        "37": {
          "source": "        }",
          "coverage": ""
        },
        "38": {
          "source": "      });",
          "coverage": ""
        },
        "39": {
          "source": "    },",
          "coverage": ""
        },
        "40": {
          "source": "    exists: function(cb){",
          "coverage": ""
        },
        "41": {
          "source": "      data.getStorage(constants.SESSION_TOKEN_STORAGE_NAME).exists(constants.SESSION_TOKEN_KEY_NAME, function(exist){",
          "coverage": 0
        },
        "42": {
          "source": "        if(cb){",
          "coverage": ""
        },
        "43": {
          "source": "          return cb(null, exist);",
          "coverage": 0
        },
        "44": {
          "source": "        }",
          "coverage": ""
        },
        "45": {
          "source": "      });",
          "coverage": ""
        },
        "46": {
          "source": "    },",
          "coverage": ""
        },
        "47": {
          "source": "    remove: function(cb){",
          "coverage": ""
        },
        "48": {
          "source": "      data.getStorage(constants.SESSION_TOKEN_STORAGE_NAME).remove(constants.SESSION_TOKEN_KEY_NAME, function(){",
          "coverage": 0
        },
        "49": {
          "source": "        if(cb){",
          "coverage": ""
        },
        "50": {
          "source": "          return cb();",
          "coverage": 0
        },
        "51": {
          "source": "        }",
          "coverage": ""
        },
        "52": {
          "source": "      });",
          "coverage": ""
        },
        "53": {
          "source": "    },",
          "coverage": ""
        },
        "54": {
          "source": "    save: function(sessionToken, cb){",
          "coverage": ""
        },
        "55": {
          "source": "      data.getStorage(constants.SESSION_TOKEN_STORAGE_NAME).save({key: constants.SESSION_TOKEN_KEY_NAME, sessionToken: sessionToken}, function(obj){",
          "coverage": 0
        },
        "56": {
          "source": "        if(cb){",
          "coverage": ""
        },
        "57": {
          "source": "          return cb();",
          "coverage": 0
        },
        "58": {
          "source": "        }",
          "coverage": ""
        },
        "59": {
          "source": "      });",
          "coverage": ""
        },
        "60": {
          "source": "    }",
          "coverage": ""
        },
        "61": {
          "source": "  }",
          "coverage": ""
        },
        "62": {
          "source": "};",
          "coverage": ""
        },
        "63": {
          "source": "",
          "coverage": ""
        },
        "64": {
          "source": "module.exports = data;",
          "coverage": 1
        },
        "65": {
          "source": "",
          "coverage": ""
        }
      }
    },
    {
      "filename": "src/modules/device.js",
      "coverage": 14.285714285714285,
      "hits": 4,
      "misses": 24,
      "sloc": 28,
      "source": {
        "1": {
          "source": "var cookies = require(\"./cookies\");",
          "coverage": 1
        },
        "2": {
          "source": "var uuidModule = require(\"./uuid\");",
          "coverage": 1
        },
        "3": {
          "source": "var logger = require(\"./logger\");",
          "coverage": 1
        },
        "4": {
          "source": "",
          "coverage": ""
        },
        "5": {
          "source": "module.exports = {",
          "coverage": 1
        },
        "6": {
          "source": "  //try to get the unique device identifier",
          "coverage": ""
        },
        "7": {
          "source": "  \"getDeviceId\": function(){",
          "coverage": ""
        },
        "8": {
          "source": "    //check for cordova/phonegap first",
          "coverage": ""
        },
        "9": {
          "source": "    if(typeof window.fhdevice !== \"undefined\" && typeof window.fhdevice.uuid !== \"undefined\"){",
          "coverage": ""
        },
        "10": {
          "source": "      return window.fhdevice.uuid;",
          "coverage": 0
        },
        "11": {
          "source": "    } else if(typeof window.device !== \"undefined\" && typeof window.device.uuid !== \"undefined\"){",
          "coverage": ""
        },
        "12": {
          "source": "      return window.device.uuid;",
          "coverage": 0
        },
        "13": {
          "source": "    }  else if(typeof navigator.device !== \"undefined\" && typeof navigator.device.uuid !== \"undefined\"){",
          "coverage": ""
        },
        "14": {
          "source": "      return navigator.device.uuid;",
          "coverage": 0
        },
        "15": {
          "source": "    } else {",
          "coverage": ""
        },
        "16": {
          "source": "      var _mock_uuid_cookie_name = \"mock_uuid\";",
          "coverage": 0
        },
        "17": {
          "source": "      var uuid = cookies.readCookieValue(_mock_uuid_cookie_name);",
          "coverage": 0
        },
        "18": {
          "source": "      if(!uuid){",
          "coverage": ""
        },
        "19": {
          "source": "        uuid = uuidModule.createUUID();",
          "coverage": 0
        },
        "20": {
          "source": "        cookies.createCookie(_mock_uuid_cookie_name, uuid);",
          "coverage": 0
        },
        "21": {
          "source": "      }",
          "coverage": ""
        },
        "22": {
          "source": "      return uuid;",
          "coverage": 0
        },
        "23": {
          "source": "    }",
          "coverage": ""
        },
        "24": {
          "source": "  },",
          "coverage": ""
        },
        "25": {
          "source": "",
          "coverage": ""
        },
        "26": {
          "source": "  //this is for fixing analytics issues when upgrading from io6 to ios7. Probably can be deprecated now",
          "coverage": ""
        },
        "27": {
          "source": "  \"getCuidMap\": function(){",
          "coverage": ""
        },
        "28": {
          "source": "    if(typeof window.fhdevice !== \"undefined\" && typeof window.fhdevice.cuidMap !== \"undefined\"){",
          "coverage": ""
        },
        "29": {
          "source": "      return window.fhdevice.cuidMap;",
          "coverage": 0
        },
        "30": {
          "source": "    } else if(typeof window.device !== \"undefined\" && typeof window.device.cuidMap !== \"undefined\"){",
          "coverage": ""
        },
        "31": {
          "source": "      return window.device.cuidMap;",
          "coverage": 0
        },
        "32": {
          "source": "    }  else if(typeof navigator.device !== \"undefined\" && typeof navigator.device.cuidMap !== \"undefined\"){",
          "coverage": ""
        },
        "33": {
          "source": "      return navigator.device.cuidMap;",
          "coverage": 0
        },
        "34": {
          "source": "    }",
          "coverage": ""
        },
        "35": {
          "source": "",
          "coverage": ""
        },
        "36": {
          "source": "    return null;",
          "coverage": 0
        },
        "37": {
          "source": "  },",
          "coverage": ""
        },
        "38": {
          "source": "",
          "coverage": ""
        },
        "39": {
          "source": "  \"getDestination\": function(){",
          "coverage": ""
        },
        "40": {
          "source": "    var destination = null;",
          "coverage": 0
        },
        "41": {
          "source": "    var platformsToTest = require(\"./platformsMap\");",
          "coverage": 0
        },
        "42": {
          "source": "",
          "coverage": ""
        },
        "43": {
          "source": "",
          "coverage": ""
        },
        "44": {
          "source": "    var userAgent = navigator.userAgent;",
          "coverage": 0
        },
        "45": {
          "source": "",
          "coverage": ""
        },
        "46": {
          "source": "    var dest_override = document.location.search.split(\"fh_destination_code=\");",
          "coverage": 0
        },
        "47": {
          "source": "    if (dest_override.length > 1) {",
          "coverage": ""
        },
        "48": {
          "source": "     destination = dest_override[1];",
          "coverage": 0
        },
        "49": {
          "source": "    } else if (typeof window.fh_destination_code !== 'undefined') {",
          "coverage": ""
        },
        "50": {
          "source": "      destination = window.fh_destination_code;",
          "coverage": 0
        },
        "51": {
          "source": "    } else {",
          "coverage": ""
        },
        "52": {
          "source": "      platformsToTest.forEach(function(testDestination){",
          "coverage": 0
        },
        "53": {
          "source": "        testDestination.test.forEach(function(destinationTest){",
          "coverage": 0
        },
        "54": {
          "source": "          if(userAgent.indexOf(destinationTest) > -1){",
          "coverage": ""
        },
        "55": {
          "source": "            destination = testDestination.destination;",
          "coverage": 0
        },
        "56": {
          "source": "          }",
          "coverage": ""
        },
        "57": {
          "source": "        });",
          "coverage": ""
        },
        "58": {
          "source": "      });",
          "coverage": ""
        },
        "59": {
          "source": "    }",
          "coverage": ""
        },
        "60": {
          "source": "",
          "coverage": ""
        },
        "61": {
          "source": "    if(destination == null){ //No user agents were found, set to default web",
          "coverage": ""
        },
        "62": {
          "source": "      destination = \"web\";",
          "coverage": 0
        },
        "63": {
          "source": "    }",
          "coverage": ""
        },
        "64": {
          "source": "",
          "coverage": ""
        },
        "65": {
          "source": "    logger.debug(\"destination = \" + destination);",
          "coverage": 0
        },
        "66": {
          "source": "",
          "coverage": ""
        },
        "67": {
          "source": "    return destination;",
          "coverage": 0
        },
        "68": {
          "source": "  }",
          "coverage": ""
        },
        "69": {
          "source": "};",
          "coverage": ""
        }
      }
    },
    {
      "filename": "src/modules/events.js",
      "coverage": 100,
      "hits": 4,
      "misses": 0,
      "sloc": 4,
      "source": {
        "1": {
          "source": "var EventEmitter = require('events').EventEmitter;",
          "coverage": 2
        },
        "2": {
          "source": "",
          "coverage": ""
        },
        "3": {
          "source": "var emitter = new EventEmitter();",
          "coverage": 2
        },
        "4": {
          "source": "emitter.setMaxListeners(0);",
          "coverage": 2
        },
        "5": {
          "source": "",
          "coverage": ""
        },
        "6": {
          "source": "module.exports = emitter;",
          "coverage": 2
        }
      }
    },
    {
      "filename": "src/modules/fhparams.js",
      "coverage": 26.82926829268293,
      "hits": 11,
      "misses": 30,
      "sloc": 41,
      "source": {
        "1": {
          "source": "var device = require(\"./device\");",
          "coverage": 1
        },
        "2": {
          "source": "var sdkversion = require(\"./sdkversion\");",
          "coverage": 1
        },
        "3": {
          "source": "var appProps = require(\"./appProps\");",
          "coverage": 1
        },
        "4": {
          "source": "var logger = require(\"./logger\");",
          "coverage": 1
        },
        "5": {
          "source": "",
          "coverage": ""
        },
        "6": {
          "source": "var defaultParams = null;",
          "coverage": 1
        },
        "7": {
          "source": "var authSessionToken = null;",
          "coverage": 1
        },
        "8": {
          "source": "//TODO: review these options, we probably only needs all of them for init calls, but we shouldn't need all of them for act calls",
          "coverage": ""
        },
        "9": {
          "source": "var buildFHParams = function(){",
          "coverage": 1
        },
        "10": {
          "source": "  if(defaultParams){",
          "coverage": ""
        },
        "11": {
          "source": "    return defaultParams;",
          "coverage": 0
        },
        "12": {
          "source": "  }",
          "coverage": ""
        },
        "13": {
          "source": "  var fhparams = {};",
          "coverage": 0
        },
        "14": {
          "source": "  fhparams.cuid = device.getDeviceId();",
          "coverage": 0
        },
        "15": {
          "source": "  fhparams.cuidMap = device.getCuidMap();",
          "coverage": 0
        },
        "16": {
          "source": "  fhparams.destination = device.getDestination();",
          "coverage": 0
        },
        "17": {
          "source": "  ",
          "coverage": ""
        },
        "18": {
          "source": "  if(window.device || navigator.device){",
          "coverage": ""
        },
        "19": {
          "source": "    fhparams.device = window.device || navigator.device;",
          "coverage": 0
        },
        "20": {
          "source": "  }",
          "coverage": ""
        },
        "21": {
          "source": "",
          "coverage": ""
        },
        "22": {
          "source": "  //backward compatible",
          "coverage": ""
        },
        "23": {
          "source": "  if (typeof window.fh_app_version !== 'undefined'){",
          "coverage": ""
        },
        "24": {
          "source": "    fhparams.app_version = fh_app_version;",
          "coverage": 0
        },
        "25": {
          "source": "  }",
          "coverage": ""
        },
        "26": {
          "source": "  if (typeof window.fh_project_version !== 'undefined'){",
          "coverage": ""
        },
        "27": {
          "source": "    fhparams.project_version = fh_project_version;",
          "coverage": 0
        },
        "28": {
          "source": "  }",
          "coverage": ""
        },
        "29": {
          "source": "  if (typeof window.fh_project_app_version !== 'undefined'){",
          "coverage": ""
        },
        "30": {
          "source": "    fhparams.project_app_version = fh_project_app_version;",
          "coverage": 0
        },
        "31": {
          "source": "  }",
          "coverage": ""
        },
        "32": {
          "source": "  fhparams.sdk_version = sdkversion();",
          "coverage": 0
        },
        "33": {
          "source": "  if(authSessionToken){",
          "coverage": ""
        },
        "34": {
          "source": "    fhparams.sessionToken = authSessionToken;",
          "coverage": 0
        },
        "35": {
          "source": "  }",
          "coverage": ""
        },
        "36": {
          "source": "",
          "coverage": ""
        },
        "37": {
          "source": "  var app_props = appProps.getAppProps();",
          "coverage": 0
        },
        "38": {
          "source": "  if(app_props){",
          "coverage": ""
        },
        "39": {
          "source": "    fhparams.appid = app_props.appid;",
          "coverage": 0
        },
        "40": {
          "source": "    fhparams.appkey = app_props.appkey;",
          "coverage": 0
        },
        "41": {
          "source": "    fhparams.projectid = app_props.projectid;",
          "coverage": 0
        },
        "42": {
          "source": "    fhparams.analyticsTag =  app_props.analyticsTag;",
          "coverage": 0
        },
        "43": {
          "source": "    fhparams.connectiontag = app_props.connectiontag;",
          "coverage": 0
        },
        "44": {
          "source": "    if(app_props.init){",
          "coverage": ""
        },
        "45": {
          "source": "      fhparams.init = typeof(app_props.init) === \"string\" ? JSON.parse(app_props.init) : app_props.init;",
          "coverage": 0
        },
        "46": {
          "source": "    }",
          "coverage": ""
        },
        "47": {
          "source": "  }",
          "coverage": ""
        },
        "48": {
          "source": "  ",
          "coverage": ""
        },
        "49": {
          "source": "  defaultParams = fhparams;",
          "coverage": 0
        },
        "50": {
          "source": "  logger.debug(\"fhparams = \", defaultParams);",
          "coverage": 0
        },
        "51": {
          "source": "  return fhparams;",
          "coverage": 0
        },
        "52": {
          "source": "};",
          "coverage": ""
        },
        "53": {
          "source": "",
          "coverage": ""
        },
        "54": {
          "source": "//TODO: deprecate this. Move to use headers instead",
          "coverage": ""
        },
        "55": {
          "source": "var addFHParams = function(params){",
          "coverage": 1
        },
        "56": {
          "source": "  var p = params || {};",
          "coverage": 0
        },
        "57": {
          "source": "  p.__fh = buildFHParams();",
          "coverage": 0
        },
        "58": {
          "source": "  return p;",
          "coverage": 0
        },
        "59": {
          "source": "};",
          "coverage": ""
        },
        "60": {
          "source": "",
          "coverage": ""
        },
        "61": {
          "source": "var getFHHeaders = function(){",
          "coverage": 1
        },
        "62": {
          "source": "  var headers = {};",
          "coverage": 0
        },
        "63": {
          "source": "  var params = buildFHParams();",
          "coverage": 0
        },
        "64": {
          "source": "  for(var name in params){",
          "coverage": ""
        },
        "65": {
          "source": "    if(params.hasOwnProperty(name)){",
          "coverage": ""
        },
        "66": {
          "source": "      headers['X-FH-' + name] = params[name];",
          "coverage": 0
        },
        "67": {
          "source": "    }",
          "coverage": ""
        },
        "68": {
          "source": "  }",
          "coverage": ""
        },
        "69": {
          "source": "  return headers;",
          "coverage": 0
        },
        "70": {
          "source": "};",
          "coverage": ""
        },
        "71": {
          "source": "",
          "coverage": ""
        },
        "72": {
          "source": "var setAuthSessionToken = function(sessionToken){",
          "coverage": 1
        },
        "73": {
          "source": "  authSessionToken = sessionToken;",
          "coverage": 0
        },
        "74": {
          "source": "  defaultParams = null;",
          "coverage": 0
        },
        "75": {
          "source": "};",
          "coverage": ""
        },
        "76": {
          "source": "",
          "coverage": ""
        },
        "77": {
          "source": "module.exports = {",
          "coverage": 1
        },
        "78": {
          "source": "  \"buildFHParams\": buildFHParams,",
          "coverage": ""
        },
        "79": {
          "source": "  \"addFHParams\": addFHParams,",
          "coverage": ""
        },
        "80": {
          "source": "  \"setAuthSessionToken\":setAuthSessionToken,",
          "coverage": ""
        },
        "81": {
          "source": "  \"getFHHeaders\": getFHHeaders",
          "coverage": ""
        },
        "82": {
          "source": "};",
          "coverage": ""
        },
        "83": {
          "source": "",
          "coverage": ""
        }
      }
    },
    {
      "filename": "src/modules/handleError.js",
      "coverage": 11.11111111111111,
      "hits": 1,
      "misses": 8,
      "sloc": 9,
      "source": {
        "1": {
          "source": "module.exports = function(fail, req, resStatus, error){",
          "coverage": 1
        },
        "2": {
          "source": "  var errraw;",
          "coverage": 0
        },
        "3": {
          "source": "  var statusCode = 0;",
          "coverage": 0
        },
        "4": {
          "source": "  if(req){",
          "coverage": ""
        },
        "5": {
          "source": "    try{",
          "coverage": ""
        },
        "6": {
          "source": "      statusCode = req.status;",
          "coverage": 0
        },
        "7": {
          "source": "      var res = JSON.parse(req.responseText);",
          "coverage": 0
        },
        "8": {
          "source": "      errraw = res.error || res.msg || res;",
          "coverage": 0
        },
        "9": {
          "source": "      if (errraw instanceof Array) {",
          "coverage": ""
        },
        "10": {
          "source": "        errraw = errraw.join('\\n');",
          "coverage": 0
        },
        "11": {
          "source": "      }",
          "coverage": ""
        },
        "12": {
          "source": "    } catch(e){",
          "coverage": ""
        },
        "13": {
          "source": "      errraw = req.responseText;",
          "coverage": 0
        },
        "14": {
          "source": "    }",
          "coverage": ""
        },
        "15": {
          "source": "  }",
          "coverage": ""
        },
        "16": {
          "source": "  if(fail){",
          "coverage": ""
        },
        "17": {
          "source": "    fail(errraw, {",
          "coverage": 0
        },
        "18": {
          "source": "      status: statusCode,",
          "coverage": ""
        },
        "19": {
          "source": "      message: resStatus,",
          "coverage": ""
        },
        "20": {
          "source": "      error: error",
          "coverage": ""
        },
        "21": {
          "source": "    });",
          "coverage": ""
        },
        "22": {
          "source": "  }",
          "coverage": ""
        },
        "23": {
          "source": "};",
          "coverage": ""
        },
        "24": {
          "source": "",
          "coverage": ""
        }
      }
    },
    {
      "filename": "src/modules/hosts.js",
      "coverage": 45.45454545454545,
      "hits": 20,
      "misses": 24,
      "sloc": 44,
      "source": {
        "1": {
          "source": "var constants = require(\"./constants\");",
          "coverage": 1
        },
        "2": {
          "source": "var appProps = require(\"./appProps\");",
          "coverage": 1
        },
        "3": {
          "source": "",
          "coverage": ""
        },
        "4": {
          "source": "function removeEndSlash(input){",
          "coverage": ""
        },
        "5": {
          "source": "  var ret = input;",
          "coverage": 1
        },
        "6": {
          "source": "  if(ret.charAt(ret.length - 1) === \"/\"){",
          "coverage": ""
        },
        "7": {
          "source": "    ret = ret.substring(0, ret.length-1);",
          "coverage": 0
        },
        "8": {
          "source": "  }",
          "coverage": ""
        },
        "9": {
          "source": "  return ret;",
          "coverage": 1
        },
        "10": {
          "source": "}",
          "coverage": ""
        },
        "11": {
          "source": "",
          "coverage": ""
        },
        "12": {
          "source": "function removeStartSlash(input){",
          "coverage": ""
        },
        "13": {
          "source": "  var ret = input;",
          "coverage": 0
        },
        "14": {
          "source": "  if(ret.length > 1 && ret.charAt(0) === \"/\"){",
          "coverage": ""
        },
        "15": {
          "source": "    ret = ret.substring(1, ret.length);",
          "coverage": 0
        },
        "16": {
          "source": "  }",
          "coverage": ""
        },
        "17": {
          "source": "  return ret;",
          "coverage": 0
        },
        "18": {
          "source": "}",
          "coverage": ""
        },
        "19": {
          "source": "",
          "coverage": ""
        },
        "20": {
          "source": "function CloudHost(cloud_props){",
          "coverage": ""
        },
        "21": {
          "source": "  this.cloud_props = cloud_props;",
          "coverage": 1
        },
        "22": {
          "source": "  this.cloud_host = undefined;",
          "coverage": 1
        },
        "23": {
          "source": "  this.app_env = null;",
          "coverage": 1
        },
        "24": {
          "source": "  this.isLegacy = false;",
          "coverage": 1
        },
        "25": {
          "source": "}",
          "coverage": ""
        },
        "26": {
          "source": "",
          "coverage": ""
        },
        "27": {
          "source": "CloudHost.prototype.getHost = function(appType){",
          "coverage": 1
        },
        "28": {
          "source": "  if(this.cloud_host){",
          "coverage": ""
        },
        "29": {
          "source": "    return this.cloud_host;",
          "coverage": 0
        },
        "30": {
          "source": "  } else {",
          "coverage": ""
        },
        "31": {
          "source": "    var url;",
          "coverage": 1
        },
        "32": {
          "source": "    var app_type;",
          "coverage": 1
        },
        "33": {
          "source": "    if(this.cloud_props && this.cloud_props.hosts){",
          "coverage": ""
        },
        "34": {
          "source": "      url = this.cloud_props.hosts.url;",
          "coverage": 1
        },
        "35": {
          "source": "",
          "coverage": ""
        },
        "36": {
          "source": "      if (typeof url === 'undefined') {",
          "coverage": ""
        },
        "37": {
          "source": "        // resolve url the old way i.e. depending on",
          "coverage": ""
        },
        "38": {
          "source": "        // -burnt in app mode",
          "coverage": ""
        },
        "39": {
          "source": "        // -returned dev or live url",
          "coverage": ""
        },
        "40": {
          "source": "        // -returned dev or live type (node or fh(rhino or proxying))",
          "coverage": ""
        },
        "41": {
          "source": "        var cloud_host = this.cloud_props.hosts.releaseCloudUrl;",
          "coverage": 0
        },
        "42": {
          "source": "        app_type = this.cloud_props.hosts.releaseCloudType;",
          "coverage": 0
        },
        "43": {
          "source": "",
          "coverage": ""
        },
        "44": {
          "source": "        if(typeof appType !== \"undefined\" && appType.indexOf(\"dev\") > -1){",
          "coverage": ""
        },
        "45": {
          "source": "          cloud_host = this.cloud_props.hosts.debugCloudUrl;",
          "coverage": 0
        },
        "46": {
          "source": "          app_type = this.cloud_props.hosts.debugCloudType;",
          "coverage": 0
        },
        "47": {
          "source": "        }",
          "coverage": ""
        },
        "48": {
          "source": "        url = cloud_host;",
          "coverage": 0
        },
        "49": {
          "source": "      }",
          "coverage": ""
        },
        "50": {
          "source": "    }",
          "coverage": ""
        },
        "51": {
          "source": "    url = removeEndSlash(url);",
          "coverage": 1
        },
        "52": {
          "source": "    this.cloud_host = url;",
          "coverage": 1
        },
        "53": {
          "source": "    if(app_type === \"fh\"){",
          "coverage": ""
        },
        "54": {
          "source": "      this.isLegacy = true;",
          "coverage": 0
        },
        "55": {
          "source": "    }",
          "coverage": ""
        },
        "56": {
          "source": "    return url;",
          "coverage": 1
        },
        "57": {
          "source": "  }",
          "coverage": ""
        },
        "58": {
          "source": "};",
          "coverage": ""
        },
        "59": {
          "source": "",
          "coverage": ""
        },
        "60": {
          "source": "CloudHost.prototype.getActUrl = function(act){",
          "coverage": 1
        },
        "61": {
          "source": "  var app_props = appProps.getAppProps() || {};",
          "coverage": 0
        },
        "62": {
          "source": "  if(typeof this.cloud_host === \"undefined\"){",
          "coverage": ""
        },
        "63": {
          "source": "    this.getHost(app_props.mode);",
          "coverage": 0
        },
        "64": {
          "source": "  }",
          "coverage": ""
        },
        "65": {
          "source": "  if(this.isLegacy){",
          "coverage": ""
        },
        "66": {
          "source": "    return this.cloud_host + constants.boxprefix + \"act/\" + this.cloud_props.domain + \"/\" + app_props.appid + \"/\" + act + \"/\" + app_props.appid;",
          "coverage": 0
        },
        "67": {
          "source": "  } else {",
          "coverage": ""
        },
        "68": {
          "source": "    return this.cloud_host + \"/cloud/\" + act;",
          "coverage": 0
        },
        "69": {
          "source": "  }",
          "coverage": ""
        },
        "70": {
          "source": "};",
          "coverage": ""
        },
        "71": {
          "source": "",
          "coverage": ""
        },
        "72": {
          "source": "CloudHost.prototype.getMBAASUrl = function(service){",
          "coverage": 1
        },
        "73": {
          "source": "  var app_props = appProps.getAppProps() || {};",
          "coverage": 0
        },
        "74": {
          "source": "  if(typeof this.cloud_host === \"undefined\"){",
          "coverage": ""
        },
        "75": {
          "source": "    this.getHost(app_props.mode);",
          "coverage": 0
        },
        "76": {
          "source": "  }",
          "coverage": ""
        },
        "77": {
          "source": "  return this.cloud_host + \"/mbaas/\" + service;",
          "coverage": 0
        },
        "78": {
          "source": "};",
          "coverage": ""
        },
        "79": {
          "source": "",
          "coverage": ""
        },
        "80": {
          "source": "CloudHost.prototype.getCloudUrl = function(path){",
          "coverage": 1
        },
        "81": {
          "source": "  var app_props = appProps.getAppProps() || {};",
          "coverage": 0
        },
        "82": {
          "source": "  if(typeof this.cloud_host === \"undefined\"){",
          "coverage": ""
        },
        "83": {
          "source": "    this.getHost(app_props.mode);",
          "coverage": 0
        },
        "84": {
          "source": "  }",
          "coverage": ""
        },
        "85": {
          "source": "  return this.cloud_host + \"/\" + removeStartSlash(path);",
          "coverage": 0
        },
        "86": {
          "source": "};",
          "coverage": ""
        },
        "87": {
          "source": "",
          "coverage": ""
        },
        "88": {
          "source": "CloudHost.prototype.getEnv = function(){",
          "coverage": 1
        },
        "89": {
          "source": "  if(this.app_env){",
          "coverage": ""
        },
        "90": {
          "source": "    return this.app_env;",
          "coverage": 0
        },
        "91": {
          "source": "  } else {",
          "coverage": ""
        },
        "92": {
          "source": "    if(this.cloud_props && this.cloud_props.hosts){",
          "coverage": ""
        },
        "93": {
          "source": "      this.app_env = this.cloud_props.hosts.environment;",
          "coverage": 0
        },
        "94": {
          "source": "    }",
          "coverage": ""
        },
        "95": {
          "source": "  }",
          "coverage": ""
        },
        "96": {
          "source": "  return this.app_env;",
          "coverage": 0
        },
        "97": {
          "source": "};",
          "coverage": ""
        },
        "98": {
          "source": "",
          "coverage": ""
        },
        "99": {
          "source": "module.exports = CloudHost;",
          "coverage": 1
        }
      }
    },
    {
      "filename": "src/modules/initializer.js",
      "coverage": 39.58333333333333,
      "hits": 19,
      "misses": 29,
      "sloc": 48,
      "source": {
        "1": {
          "source": "var loadScript = require(\"./loadScript\");",
          "coverage": 1
        },
        "2": {
          "source": "var consts = require(\"./constants\");",
          "coverage": 1
        },
        "3": {
          "source": "var fhparams = require(\"./fhparams\");",
          "coverage": 1
        },
        "4": {
          "source": "var ajax = require(\"./ajax\");",
          "coverage": 1
        },
        "5": {
          "source": "var handleError = require(\"./handleError\");",
          "coverage": 1
        },
        "6": {
          "source": "var logger = require(\"./logger\");",
          "coverage": 1
        },
        "7": {
          "source": "var hashFunc = require(\"./security/hash\");",
          "coverage": 1
        },
        "8": {
          "source": "var appProps = require(\"./appProps\");",
          "coverage": 1
        },
        "9": {
          "source": "var constants = require(\"./constants\");",
          "coverage": 1
        },
        "10": {
          "source": "var events = require(\"./events\");",
          "coverage": 1
        },
        "11": {
          "source": "var data = require('./data');",
          "coverage": 1
        },
        "12": {
          "source": "",
          "coverage": ""
        },
        "13": {
          "source": "var init = function(cb) {",
          "coverage": 1
        },
        "14": {
          "source": "  appProps.load(function(err, data) {",
          "coverage": 1
        },
        "15": {
          "source": "    if (err) {",
          "coverage": ""
        },
        "16": {
          "source": "      return cb(err);",
          "coverage": 0
        },
        "17": {
          "source": "    }",
          "coverage": ""
        },
        "18": {
          "source": "    // Emit internal config loaded event - SDK will now set appprops",
          "coverage": ""
        },
        "19": {
          "source": "    events.emit(constants.INTERNAL_CONFIG_LOADED_EVENT, null, data);",
          "coverage": 1
        },
        "20": {
          "source": "    return loadCloudProps(data, cb);",
          "coverage": 1
        },
        "21": {
          "source": "  });",
          "coverage": ""
        },
        "22": {
          "source": "};",
          "coverage": ""
        },
        "23": {
          "source": "",
          "coverage": ""
        },
        "24": {
          "source": "var loadCloudProps = function(app_props, callback) {",
          "coverage": 1
        },
        "25": {
          "source": "  if (app_props.loglevel) {",
          "coverage": ""
        },
        "26": {
          "source": "    logger.setLevel(app_props.loglevel);",
          "coverage": 0
        },
        "27": {
          "source": "  }",
          "coverage": ""
        },
        "28": {
          "source": "  // If local - shortcircuit the init - just return the host",
          "coverage": ""
        },
        "29": {
          "source": "  if (app_props.local) {",
          "coverage": ""
        },
        "30": {
          "source": "    var res = {",
          "coverage": 1
        },
        "31": {
          "source": "      \"domain\": \"local\",",
          "coverage": ""
        },
        "32": {
          "source": "      \"firstTime\": false,",
          "coverage": ""
        },
        "33": {
          "source": "      \"hosts\": {",
          "coverage": ""
        },
        "34": {
          "source": "        \"debugCloudType\": \"node\",",
          "coverage": ""
        },
        "35": {
          "source": "        \"debugCloudUrl\": app_props.host,",
          "coverage": ""
        },
        "36": {
          "source": "        \"releaseCloudType\": \"node\",",
          "coverage": ""
        },
        "37": {
          "source": "        \"releaseCloudUrl\": app_props.host,",
          "coverage": ""
        },
        "38": {
          "source": "        \"type\": \"cloud_nodejs\",",
          "coverage": ""
        },
        "39": {
          "source": "        \"url\": app_props.host",
          "coverage": ""
        },
        "40": {
          "source": "      },",
          "coverage": ""
        },
        "41": {
          "source": "      \"init\": {",
          "coverage": ""
        },
        "42": {
          "source": "        \"trackId\": \"000000000000000000000000\"",
          "coverage": ""
        },
        "43": {
          "source": "      },",
          "coverage": ""
        },
        "44": {
          "source": "      \"status\": \"ok\"",
          "coverage": ""
        },
        "45": {
          "source": "    };",
          "coverage": ""
        },
        "46": {
          "source": "",
          "coverage": ""
        },
        "47": {
          "source": "    return callback(null, {",
          "coverage": 1
        },
        "48": {
          "source": "      cloud: res",
          "coverage": ""
        },
        "49": {
          "source": "    });",
          "coverage": ""
        },
        "50": {
          "source": "  }",
          "coverage": ""
        },
        "51": {
          "source": "",
          "coverage": ""
        },
        "52": {
          "source": "",
          "coverage": ""
        },
        "53": {
          "source": "  //now we have app props, add the fileStorageAdapter",
          "coverage": ""
        },
        "54": {
          "source": "  data.addFileStorageAdapter(app_props, hashFunc);",
          "coverage": 0
        },
        "55": {
          "source": "  var doInit = function(path, appProps, savedHost, storage) {",
          "coverage": 0
        },
        "56": {
          "source": "    var data = fhparams.buildFHParams();",
          "coverage": 0
        },
        "57": {
          "source": "",
          "coverage": ""
        },
        "58": {
          "source": "    ajax({",
          "coverage": 0
        },
        "59": {
          "source": "      \"url\": path,",
          "coverage": ""
        },
        "60": {
          "source": "      \"type\": \"POST\",",
          "coverage": ""
        },
        "61": {
          "source": "      \"tryJSONP\": true,",
          "coverage": ""
        },
        "62": {
          "source": "      \"dataType\": \"json\",",
          "coverage": ""
        },
        "63": {
          "source": "      \"contentType\": \"application/json\",",
          "coverage": ""
        },
        "64": {
          "source": "      \"data\": JSON.stringify(data),",
          "coverage": ""
        },
        "65": {
          "source": "      \"timeout\": appProps.timeout,",
          "coverage": ""
        },
        "66": {
          "source": "      \"success\": function(initRes) {",
          "coverage": ""
        },
        "67": {
          "source": "        if (storage) {",
          "coverage": ""
        },
        "68": {
          "source": "          storage.save({",
          "coverage": 0
        },
        "69": {
          "source": "            key: \"fh_init\",",
          "coverage": ""
        },
        "70": {
          "source": "            value: initRes",
          "coverage": ""
        },
        "71": {
          "source": "          }, function() {});",
          "coverage": ""
        },
        "72": {
          "source": "        }",
          "coverage": ""
        },
        "73": {
          "source": "        if (callback) {",
          "coverage": ""
        },
        "74": {
          "source": "          callback(null, {",
          "coverage": 0
        },
        "75": {
          "source": "            cloud: initRes",
          "coverage": ""
        },
        "76": {
          "source": "          });",
          "coverage": ""
        },
        "77": {
          "source": "        }",
          "coverage": ""
        },
        "78": {
          "source": "      },",
          "coverage": ""
        },
        "79": {
          "source": "      \"error\": function(req, statusText, error) {",
          "coverage": ""
        },
        "80": {
          "source": "        var errormsg = \"unknown\";",
          "coverage": 0
        },
        "81": {
          "source": "        if (req) {",
          "coverage": ""
        },
        "82": {
          "source": "          errormsg = req.status + \" - \" + req.responseText;",
          "coverage": 0
        },
        "83": {
          "source": "        }",
          "coverage": ""
        },
        "84": {
          "source": "        logger.error(\"App init returned error : \" + errormsg);",
          "coverage": 0
        },
        "85": {
          "source": "        //use the cached host if we have a copy",
          "coverage": ""
        },
        "86": {
          "source": "        if (savedHost && req.status !== 400) {",
          "coverage": ""
        },
        "87": {
          "source": "          logger.info(\"Using cached host: \" + JSON.stringify(savedHost));",
          "coverage": 0
        },
        "88": {
          "source": "          if (callback) {",
          "coverage": ""
        },
        "89": {
          "source": "            callback(null, {",
          "coverage": 0
        },
        "90": {
          "source": "              cloud: savedHost",
          "coverage": ""
        },
        "91": {
          "source": "            });",
          "coverage": ""
        },
        "92": {
          "source": "          }",
          "coverage": ""
        },
        "93": {
          "source": "        } else {",
          "coverage": ""
        },
        "94": {
          "source": "          if (req.status === 400) {",
          "coverage": ""
        },
        "95": {
          "source": "            logger.error(req.responseText);",
          "coverage": 0
        },
        "96": {
          "source": "          } else {",
          "coverage": ""
        },
        "97": {
          "source": "            logger.error(\"No cached host found. Init failed.\");",
          "coverage": 0
        },
        "98": {
          "source": "          }",
          "coverage": ""
        },
        "99": {
          "source": "          handleError(function(msg, err) {",
          "coverage": 0
        },
        "100": {
          "source": "            if (callback) {",
          "coverage": ""
        },
        "101": {
          "source": "              callback({",
          "coverage": 0
        },
        "102": {
          "source": "                error: err,",
          "coverage": ""
        },
        "103": {
          "source": "                message: msg",
          "coverage": ""
        },
        "104": {
          "source": "              });",
          "coverage": ""
        },
        "105": {
          "source": "            }",
          "coverage": ""
        },
        "106": {
          "source": "          }, req, statusText, error);",
          "coverage": ""
        },
        "107": {
          "source": "        }",
          "coverage": ""
        },
        "108": {
          "source": "      }",
          "coverage": ""
        },
        "109": {
          "source": "    });",
          "coverage": ""
        },
        "110": {
          "source": "  };",
          "coverage": ""
        },
        "111": {
          "source": "",
          "coverage": ""
        },
        "112": {
          "source": "  var storage = null;",
          "coverage": 0
        },
        "113": {
          "source": "  var path = app_props.host + consts.boxprefix + \"app/init\";",
          "coverage": 0
        },
        "114": {
          "source": "  try {",
          "coverage": ""
        },
        "115": {
          "source": "    storage = data.getStorage(\"fh_init_storage\", typeof Titanium !== \"undefined\"?['titanium']:null);",
          "coverage": 0
        },
        "116": {
          "source": "    storage.get('fh_init', function(storage_res) {",
          "coverage": 0
        },
        "117": {
          "source": "      var savedHost = null;",
          "coverage": 0
        },
        "118": {
          "source": "      if (storage_res && storage_res.value !== null && typeof(storage_res.value) !== \"undefined\" && storage_res !== \"\") {",
          "coverage": ""
        },
        "119": {
          "source": "        storage_res = typeof(storage_res) === \"string\" ? JSON.parse(storage_res) : storage_res;",
          "coverage": 0
        },
        "120": {
          "source": "        storage_res.value = typeof(storage_res.value) === \"string\" ? JSON.parse(storage_res.value) : storage_res.value;",
          "coverage": 0
        },
        "121": {
          "source": "        if (storage_res.value.init) {",
          "coverage": ""
        },
        "122": {
          "source": "          app_props.init = storage_res.value.init;",
          "coverage": 0
        },
        "123": {
          "source": "        } else {",
          "coverage": ""
        },
        "124": {
          "source": "          //keep it backward compatible.",
          "coverage": ""
        },
        "125": {
          "source": "          app_props.init = typeof(storage_res.value) === \"string\" ? JSON.parse(storage_res.value) : storage_res.value;",
          "coverage": 0
        },
        "126": {
          "source": "        }",
          "coverage": ""
        },
        "127": {
          "source": "        if (storage_res.value.hosts) {",
          "coverage": ""
        },
        "128": {
          "source": "          savedHost = storage_res.value;",
          "coverage": 0
        },
        "129": {
          "source": "        }",
          "coverage": ""
        },
        "130": {
          "source": "      }",
          "coverage": ""
        },
        "131": {
          "source": "",
          "coverage": ""
        },
        "132": {
          "source": "      doInit(path, app_props, savedHost, storage);",
          "coverage": 0
        },
        "133": {
          "source": "    });",
          "coverage": ""
        },
        "134": {
          "source": "  } catch (e) {",
          "coverage": ""
        },
        "135": {
          "source": "    //for whatever reason (e.g. localStorage is disabled) Lawnchair is failed to init, just do the init",
          "coverage": ""
        },
        "136": {
          "source": "    doInit(path, app_props, null, null);",
          "coverage": 0
        },
        "137": {
          "source": "  }",
          "coverage": ""
        },
        "138": {
          "source": "};",
          "coverage": ""
        },
        "139": {
          "source": "",
          "coverage": ""
        },
        "140": {
          "source": "module.exports = {",
          "coverage": 1
        },
        "141": {
          "source": "  \"init\": init,",
          "coverage": ""
        },
        "142": {
          "source": "  \"loadCloudProps\": loadCloudProps",
          "coverage": ""
        },
        "143": {
          "source": "};",
          "coverage": ""
        },
        "144": {
          "source": "",
          "coverage": ""
        }
      }
    },
    {
      "filename": "src/modules/lawnchair-ext.js",
      "coverage": 3.076923076923077,
      "hits": 2,
      "misses": 63,
      "sloc": 65,
      "source": {
        "1": {
          "source": "var fileStorageAdapter = function (app_props, hashFunc) {",
          "coverage": 1
        },
        "2": {
          "source": "  // private methods",
          "coverage": ""
        },
        "3": {
          "source": "",
          "coverage": ""
        },
        "4": {
          "source": "  function doLog(mess){",
          "coverage": ""
        },
        "5": {
          "source": "    if(console){",
          "coverage": ""
        },
        "6": {
          "source": "      console.log(mess);",
          "coverage": 0
        },
        "7": {
          "source": "    }",
          "coverage": ""
        },
        "8": {
          "source": "  }",
          "coverage": ""
        },
        "9": {
          "source": "",
          "coverage": ""
        },
        "10": {
          "source": "  var fail = function (e, i) {",
          "coverage": 0
        },
        "11": {
          "source": "    if(console) {",
          "coverage": ""
        },
        "12": {
          "source": "      console.log('error in file system adapter !', e, i);",
          "coverage": 0
        },
        "13": {
          "source": "    } else {",
          "coverage": ""
        },
        "14": {
          "source": "      throw e;",
          "coverage": 0
        },
        "15": {
          "source": "    }",
          "coverage": ""
        },
        "16": {
          "source": "  };",
          "coverage": ""
        },
        "17": {
          "source": "",
          "coverage": ""
        },
        "18": {
          "source": "",
          "coverage": ""
        },
        "19": {
          "source": "  function filenameForKey(key, cb) {",
          "coverage": ""
        },
        "20": {
          "source": "    key = app_props.appid + key;",
          "coverage": 0
        },
        "21": {
          "source": "",
          "coverage": ""
        },
        "22": {
          "source": "    hashFunc({",
          "coverage": 0
        },
        "23": {
          "source": "      algorithm: \"MD5\",",
          "coverage": ""
        },
        "24": {
          "source": "      text: key",
          "coverage": ""
        },
        "25": {
          "source": "    }, function(result) {",
          "coverage": ""
        },
        "26": {
          "source": "      var filename = result.hashvalue + '.txt';",
          "coverage": 0
        },
        "27": {
          "source": "      if (typeof navigator.externalstorage !== \"undefined\") {",
          "coverage": ""
        },
        "28": {
          "source": "        navigator.externalstorage.enable(function handleSuccess(res){",
          "coverage": 0
        },
        "29": {
          "source": "          var path = filename;",
          "coverage": 0
        },
        "30": {
          "source": "          if(res.path ) {",
          "coverage": ""
        },
        "31": {
          "source": "            path = res.path;",
          "coverage": 0
        },
        "32": {
          "source": "            if(!path.match(/\\/$/)) {",
          "coverage": ""
        },
        "33": {
          "source": "              path += '/';",
          "coverage": 0
        },
        "34": {
          "source": "            }",
          "coverage": ""
        },
        "35": {
          "source": "            path += filename;",
          "coverage": 0
        },
        "36": {
          "source": "          }",
          "coverage": ""
        },
        "37": {
          "source": "          filename = path;",
          "coverage": 0
        },
        "38": {
          "source": "          return cb(filename);",
          "coverage": 0
        },
        "39": {
          "source": "        },function handleError(err){",
          "coverage": ""
        },
        "40": {
          "source": "          return cb(filename);",
          "coverage": 0
        },
        "41": {
          "source": "        });",
          "coverage": ""
        },
        "42": {
          "source": "      } else {",
          "coverage": ""
        },
        "43": {
          "source": "        doLog('filenameForKey key=' + key+ ' , Filename: ' + filename);",
          "coverage": 0
        },
        "44": {
          "source": "        return cb(filename);",
          "coverage": 0
        },
        "45": {
          "source": "      }",
          "coverage": ""
        },
        "46": {
          "source": "    });",
          "coverage": ""
        },
        "47": {
          "source": "  }",
          "coverage": ""
        },
        "48": {
          "source": "",
          "coverage": ""
        },
        "49": {
          "source": "  return {",
          "coverage": 0
        },
        "50": {
          "source": "",
          "coverage": ""
        },
        "51": {
          "source": "    valid: function () { return !!(window.requestFileSystem); },",
          "coverage": 0
        },
        "52": {
          "source": "",
          "coverage": ""
        },
        "53": {
          "source": "    init : function (options, callback){",
          "coverage": ""
        },
        "54": {
          "source": "      //calls the parent function fn and applies this scope",
          "coverage": ""
        },
        "55": {
          "source": "      if(options && 'function' === typeof options.fail ) {",
          "coverage": ""
        },
        "56": {
          "source": "        fail = options.fail;",
          "coverage": 0
        },
        "57": {
          "source": "      }",
          "coverage": ""
        },
        "58": {
          "source": "      if (callback) {",
          "coverage": ""
        },
        "59": {
          "source": "        this.fn(this.name, callback).call(this, this);",
          "coverage": 0
        },
        "60": {
          "source": "      }",
          "coverage": ""
        },
        "61": {
          "source": "    },",
          "coverage": ""
        },
        "62": {
          "source": "",
          "coverage": ""
        },
        "63": {
          "source": "    keys: function (callback){",
          "coverage": ""
        },
        "64": {
          "source": "      throw \"Currently not supported\";",
          "coverage": 0
        },
        "65": {
          "source": "    },",
          "coverage": ""
        },
        "66": {
          "source": "",
          "coverage": ""
        },
        "67": {
          "source": "    save : function (obj, callback){",
          "coverage": ""
        },
        "68": {
          "source": "      var key = obj.key;",
          "coverage": 0
        },
        "69": {
          "source": "      var value = obj.val||obj.value;",
          "coverage": 0
        },
        "70": {
          "source": "      filenameForKey(key, function(hash) {",
          "coverage": 0
        },
        "71": {
          "source": "        window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, function gotFS(fileSystem) {",
          "coverage": 0
        },
        "72": {
          "source": "",
          "coverage": ""
        },
        "73": {
          "source": "          fileSystem.root.getFile(hash, {",
          "coverage": 0
        },
        "74": {
          "source": "            create: true",
          "coverage": ""
        },
        "75": {
          "source": "          }, function gotFileEntry(fileEntry) {",
          "coverage": ""
        },
        "76": {
          "source": "            fileEntry.createWriter(function gotFileWriter(writer) {",
          "coverage": 0
        },
        "77": {
          "source": "              writer.onwrite = function() {",
          "coverage": 0
        },
        "78": {
          "source": "                return callback({",
          "coverage": 0
        },
        "79": {
          "source": "                  key: key,",
          "coverage": ""
        },
        "80": {
          "source": "                  val: value",
          "coverage": ""
        },
        "81": {
          "source": "                });",
          "coverage": ""
        },
        "82": {
          "source": "              };",
          "coverage": ""
        },
        "83": {
          "source": "              writer.write(value);",
          "coverage": 0
        },
        "84": {
          "source": "            }, function() {",
          "coverage": ""
        },
        "85": {
          "source": "              fail('[save] Failed to create file writer');",
          "coverage": 0
        },
        "86": {
          "source": "            });",
          "coverage": ""
        },
        "87": {
          "source": "          }, function() {",
          "coverage": ""
        },
        "88": {
          "source": "            fail('[save] Failed to getFile');",
          "coverage": 0
        },
        "89": {
          "source": "          });",
          "coverage": ""
        },
        "90": {
          "source": "        }, function() {",
          "coverage": ""
        },
        "91": {
          "source": "          fail('[save] Failed to requestFileSystem');",
          "coverage": 0
        },
        "92": {
          "source": "        });",
          "coverage": ""
        },
        "93": {
          "source": "      });",
          "coverage": ""
        },
        "94": {
          "source": "    },",
          "coverage": ""
        },
        "95": {
          "source": "",
          "coverage": ""
        },
        "96": {
          "source": "    batch : function (records, callback){",
          "coverage": ""
        },
        "97": {
          "source": "      throw \"Currently not supported\";",
          "coverage": 0
        },
        "98": {
          "source": "    },",
          "coverage": ""
        },
        "99": {
          "source": "",
          "coverage": ""
        },
        "100": {
          "source": "    get : function (key, callback){",
          "coverage": ""
        },
        "101": {
          "source": "      filenameForKey(key, function(hash) {",
          "coverage": 0
        },
        "102": {
          "source": "        window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, function gotFS(fileSystem) {",
          "coverage": 0
        },
        "103": {
          "source": "          fileSystem.root.getFile(hash, {}, function gotFileEntry(fileEntry) {",
          "coverage": 0
        },
        "104": {
          "source": "            fileEntry.file(function gotFile(file) {",
          "coverage": 0
        },
        "105": {
          "source": "              var reader = new FileReader();",
          "coverage": 0
        },
        "106": {
          "source": "              reader.onloadend = function (evt) {",
          "coverage": 0
        },
        "107": {
          "source": "                var text = evt.target.result;",
          "coverage": 0
        },
        "108": {
          "source": "                // Check for URLencoded",
          "coverage": ""
        },
        "109": {
          "source": "                // PG 2.2 bug in readAsText()",
          "coverage": ""
        },
        "110": {
          "source": "                try {",
          "coverage": ""
        },
        "111": {
          "source": "                  text = decodeURIComponent(text);",
          "coverage": 0
        },
        "112": {
          "source": "                } catch (e) {",
          "coverage": ""
        },
        "113": {
          "source": "                  // Swallow exception if not URLencoded",
          "coverage": ""
        },
        "114": {
          "source": "                  // Just use the result",
          "coverage": ""
        },
        "115": {
          "source": "                }",
          "coverage": ""
        },
        "116": {
          "source": "                return callback({",
          "coverage": 0
        },
        "117": {
          "source": "                  key: key,",
          "coverage": ""
        },
        "118": {
          "source": "                  val: text",
          "coverage": ""
        },
        "119": {
          "source": "                });",
          "coverage": ""
        },
        "120": {
          "source": "              };",
          "coverage": ""
        },
        "121": {
          "source": "              reader.readAsText(file);",
          "coverage": 0
        },
        "122": {
          "source": "            }, function() {",
          "coverage": ""
        },
        "123": {
          "source": "              fail('[load] Failed to getFile');",
          "coverage": 0
        },
        "124": {
          "source": "            });",
          "coverage": ""
        },
        "125": {
          "source": "          }, function() {",
          "coverage": ""
        },
        "126": {
          "source": "            // Success callback on key load failure",
          "coverage": ""
        },
        "127": {
          "source": "            callback({",
          "coverage": 0
        },
        "128": {
          "source": "              key: key,",
          "coverage": ""
        },
        "129": {
          "source": "              val: null",
          "coverage": ""
        },
        "130": {
          "source": "            });",
          "coverage": ""
        },
        "131": {
          "source": "          });",
          "coverage": ""
        },
        "132": {
          "source": "        }, function() {",
          "coverage": ""
        },
        "133": {
          "source": "          fail('[load] Failed to get fileSystem');",
          "coverage": 0
        },
        "134": {
          "source": "        });",
          "coverage": ""
        },
        "135": {
          "source": "      });",
          "coverage": ""
        },
        "136": {
          "source": "    },",
          "coverage": ""
        },
        "137": {
          "source": "",
          "coverage": ""
        },
        "138": {
          "source": "    exists : function (key, callback){",
          "coverage": ""
        },
        "139": {
          "source": "      filenameForKey(key,function (hash){",
          "coverage": 0
        },
        "140": {
          "source": "        window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, function gotFS(fileSystem) {",
          "coverage": 0
        },
        "141": {
          "source": "          fileSystem.root.getFile(hash, {},",
          "coverage": 0
        },
        "142": {
          "source": "            function gotFileEntry(fileEntry) {",
          "coverage": ""
        },
        "143": {
          "source": "              return callback(true);",
          "coverage": 0
        },
        "144": {
          "source": "            }, function (err){",
          "coverage": ""
        },
        "145": {
          "source": "              return callback(false);",
          "coverage": 0
        },
        "146": {
          "source": "            });",
          "coverage": ""
        },
        "147": {
          "source": "        });",
          "coverage": ""
        },
        "148": {
          "source": "      });",
          "coverage": ""
        },
        "149": {
          "source": "    },",
          "coverage": ""
        },
        "150": {
          "source": "",
          "coverage": ""
        },
        "151": {
          "source": "    all : function (callback){",
          "coverage": ""
        },
        "152": {
          "source": "      throw \"Currently not supported\";",
          "coverage": 0
        },
        "153": {
          "source": "    },",
          "coverage": ""
        },
        "154": {
          "source": "",
          "coverage": ""
        },
        "155": {
          "source": "    remove : function (key, callback){",
          "coverage": ""
        },
        "156": {
          "source": "      filenameForKey(key, function(hash) {",
          "coverage": 0
        },
        "157": {
          "source": "",
          "coverage": ""
        },
        "158": {
          "source": "        window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, function gotFS(fileSystem) {",
          "coverage": 0
        },
        "159": {
          "source": "          fileSystem.root.getFile(hash, {}, function gotFileEntry(fileEntry) {",
          "coverage": 0
        },
        "160": {
          "source": "",
          "coverage": ""
        },
        "161": {
          "source": "            fileEntry.remove(function() {",
          "coverage": 0
        },
        "162": {
          "source": "              return callback({",
          "coverage": 0
        },
        "163": {
          "source": "                key: key,",
          "coverage": ""
        },
        "164": {
          "source": "                val: null",
          "coverage": ""
        },
        "165": {
          "source": "              });",
          "coverage": ""
        },
        "166": {
          "source": "            }, function() {",
          "coverage": ""
        },
        "167": {
          "source": "              fail('[remove] Failed to remove file');",
          "coverage": 0
        },
        "168": {
          "source": "            });",
          "coverage": ""
        },
        "169": {
          "source": "          }, function() {",
          "coverage": ""
        },
        "170": {
          "source": "            fail('[remove] Failed to getFile');",
          "coverage": 0
        },
        "171": {
          "source": "          });",
          "coverage": ""
        },
        "172": {
          "source": "        }, function() {",
          "coverage": ""
        },
        "173": {
          "source": "          fail('[remove] Failed to get fileSystem');",
          "coverage": 0
        },
        "174": {
          "source": "        });",
          "coverage": ""
        },
        "175": {
          "source": "      });",
          "coverage": ""
        },
        "176": {
          "source": "    },",
          "coverage": ""
        },
        "177": {
          "source": "",
          "coverage": ""
        },
        "178": {
          "source": "    nuke : function (callback){",
          "coverage": ""
        },
        "179": {
          "source": "      throw \"Currently not supported\";",
          "coverage": 0
        },
        "180": {
          "source": "    }",
          "coverage": ""
        },
        "181": {
          "source": "",
          "coverage": ""
        },
        "182": {
          "source": "",
          "coverage": ""
        },
        "183": {
          "source": "  };",
          "coverage": ""
        },
        "184": {
          "source": "};",
          "coverage": ""
        },
        "185": {
          "source": "",
          "coverage": ""
        },
        "186": {
          "source": "module.exports = {",
          "coverage": 1
        },
        "187": {
          "source": "  fileStorageAdapter: fileStorageAdapter",
          "coverage": ""
        },
        "188": {
          "source": "};",
          "coverage": ""
        }
      }
    },
    {
      "filename": "src/modules/loadScript.js",
      "coverage": 7.6923076923076925,
      "hits": 1,
      "misses": 12,
      "sloc": 13,
      "source": {
        "1": {
          "source": "module.exports = function (url, callback) {",
          "coverage": 1
        },
        "2": {
          "source": "  var script;",
          "coverage": 0
        },
        "3": {
          "source": "  var head = document.head || document.getElementsByTagName(\"head\")[0] || document.documentElement;",
          "coverage": 0
        },
        "4": {
          "source": "  script = document.createElement(\"script\");",
          "coverage": 0
        },
        "5": {
          "source": "  script.async = \"async\";",
          "coverage": 0
        },
        "6": {
          "source": "  script.src = url;",
          "coverage": 0
        },
        "7": {
          "source": "  script.type = \"text/javascript\";",
          "coverage": 0
        },
        "8": {
          "source": "  script.onload = script.onreadystatechange = function () {",
          "coverage": 0
        },
        "9": {
          "source": "    if (!script.readyState || /loaded|complete/.test(script.readyState)) {",
          "coverage": ""
        },
        "10": {
          "source": "      script.onload = script.onreadystatechange = null;",
          "coverage": 0
        },
        "11": {
          "source": "      if (head && script.parentNode) {",
          "coverage": ""
        },
        "12": {
          "source": "        head.removeChild(script);",
          "coverage": 0
        },
        "13": {
          "source": "      }",
          "coverage": ""
        },
        "14": {
          "source": "      script = undefined;",
          "coverage": 0
        },
        "15": {
          "source": "      if (callback && typeof callback === \"function\") {",
          "coverage": ""
        },
        "16": {
          "source": "        callback();",
          "coverage": 0
        },
        "17": {
          "source": "      }",
          "coverage": ""
        },
        "18": {
          "source": "    }",
          "coverage": ""
        },
        "19": {
          "source": "  };",
          "coverage": ""
        },
        "20": {
          "source": "  head.insertBefore(script, head.firstChild);",
          "coverage": 0
        },
        "21": {
          "source": "};",
          "coverage": ""
        },
        "22": {
          "source": "",
          "coverage": ""
        }
      }
    },
    {
      "filename": "src/modules/logger.js",
      "coverage": 100,
      "hits": 4,
      "misses": 0,
      "sloc": 4,
      "source": {
        "1": {
          "source": "var console = require('console');",
          "coverage": 2
        },
        "2": {
          "source": "var log = require('loglevel');",
          "coverage": 2
        },
        "3": {
          "source": "",
          "coverage": ""
        },
        "4": {
          "source": "log.setLevel('info');",
          "coverage": 2
        },
        "5": {
          "source": "",
          "coverage": ""
        },
        "6": {
          "source": "/**",
          "coverage": ""
        },
        "7": {
          "source": " * APIs:",
          "coverage": ""
        },
        "8": {
          "source": " * see https://github.com/pimterry/loglevel.",
          "coverage": ""
        },
        "9": {
          "source": " * In short, you can use:",
          "coverage": ""
        },
        "10": {
          "source": " * log.setLevel(loglevel) - default to info",
          "coverage": ""
        },
        "11": {
          "source": " * log.enableAll() - enable all log messages",
          "coverage": ""
        },
        "12": {
          "source": " * log.disableAll() - disable all log messages",
          "coverage": ""
        },
        "13": {
          "source": " *",
          "coverage": ""
        },
        "14": {
          "source": " * log.trace(msg)",
          "coverage": ""
        },
        "15": {
          "source": " * log.debug(msg)",
          "coverage": ""
        },
        "16": {
          "source": " * log.info(msg)",
          "coverage": ""
        },
        "17": {
          "source": " * log.warn(msg)",
          "coverage": ""
        },
        "18": {
          "source": " * log.error(msg)",
          "coverage": ""
        },
        "19": {
          "source": " *",
          "coverage": ""
        },
        "20": {
          "source": " * Available levels: { \"TRACE\": 0, \"DEBUG\": 1, \"INFO\": 2, \"WARN\": 3, \"ERROR\": 4, \"SILENT\": 5}",
          "coverage": ""
        },
        "21": {
          "source": " * Use either string or integer value",
          "coverage": ""
        },
        "22": {
          "source": " */",
          "coverage": ""
        },
        "23": {
          "source": "module.exports = log;",
          "coverage": 2
        }
      }
    },
    {
      "filename": "src/modules/queryMap.js",
      "coverage": 100,
      "hits": 10,
      "misses": 0,
      "sloc": 10,
      "source": {
        "1": {
          "source": "module.exports = function(url) {",
          "coverage": 2
        },
        "2": {
          "source": "  var qmap = {};",
          "coverage": 4
        },
        "3": {
          "source": "  var i = url.split(\"?\");",
          "coverage": 4
        },
        "4": {
          "source": "  if (i.length === 2) {",
          "coverage": ""
        },
        "5": {
          "source": "    var queryString = i[1];",
          "coverage": 4
        },
        "6": {
          "source": "    var pairs = queryString.split(\"&\");",
          "coverage": 4
        },
        "7": {
          "source": "    qmap = {};",
          "coverage": 4
        },
        "8": {
          "source": "    for (var p = 0; p < pairs.length; p++) {",
          "coverage": ""
        },
        "9": {
          "source": "      var q = pairs[p];",
          "coverage": 8
        },
        "10": {
          "source": "      var qp = q.split(\"=\");",
          "coverage": 8
        },
        "11": {
          "source": "      qmap[qp[0]] = qp[1];",
          "coverage": 8
        },
        "12": {
          "source": "    }",
          "coverage": ""
        },
        "13": {
          "source": "  }",
          "coverage": ""
        },
        "14": {
          "source": "  return qmap;",
          "coverage": 4
        },
        "15": {
          "source": "};",
          "coverage": ""
        }
      }
    },
    {
      "filename": "src/modules/sdkversion.js",
      "coverage": 33.33333333333333,
      "hits": 2,
      "misses": 4,
      "sloc": 6,
      "source": {
        "1": {
          "source": "var constants = require(\"./constants\");",
          "coverage": 1
        },
        "2": {
          "source": "",
          "coverage": ""
        },
        "3": {
          "source": "module.exports = function() {",
          "coverage": 1
        },
        "4": {
          "source": "  var type = \"FH_JS_SDK\";",
          "coverage": 0
        },
        "5": {
          "source": "  if (typeof window.fh_destination_code !== 'undefined') {",
          "coverage": ""
        },
        "6": {
          "source": "    type = \"FH_HYBRID_SDK\";",
          "coverage": 0
        },
        "7": {
          "source": "  } else if(window.PhoneGap || window.cordova) {",
          "coverage": ""
        },
        "8": {
          "source": "    type = \"FH_PHONEGAP_SDK\";",
          "coverage": 0
        },
        "9": {
          "source": "  }",
          "coverage": ""
        },
        "10": {
          "source": "  return type + \"/\" + constants.sdk_version;",
          "coverage": 0
        },
        "11": {
          "source": "};",
          "coverage": ""
        },
        "12": {
          "source": "",
          "coverage": ""
        }
      }
    },
    {
      "filename": "src/modules/security/aes-keygen.js",
      "coverage": 30,
      "hits": 6,
      "misses": 14,
      "sloc": 20,
      "source": {
        "1": {
          "source": "var rsa = require(\"../../../libs/rsa\");",
          "coverage": 1
        },
        "2": {
          "source": "var SecureRandom = rsa.SecureRandom;",
          "coverage": 1
        },
        "3": {
          "source": "var byte2Hex = rsa.byte2Hex;",
          "coverage": 1
        },
        "4": {
          "source": "",
          "coverage": ""
        },
        "5": {
          "source": "var generateRandomKey = function(keysize){",
          "coverage": 1
        },
        "6": {
          "source": "  var r = new SecureRandom();",
          "coverage": 0
        },
        "7": {
          "source": "  var key = new Array(keysize);",
          "coverage": 0
        },
        "8": {
          "source": "  r.nextBytes(key);",
          "coverage": 0
        },
        "9": {
          "source": "  var result = \"\";",
          "coverage": 0
        },
        "10": {
          "source": "  for(var i=0;i<key.length;i++){",
          "coverage": ""
        },
        "11": {
          "source": "    result += byte2Hex(key[i]);",
          "coverage": 0
        },
        "12": {
          "source": "  }",
          "coverage": ""
        },
        "13": {
          "source": "  return result;",
          "coverage": 0
        },
        "14": {
          "source": "};",
          "coverage": ""
        },
        "15": {
          "source": "",
          "coverage": ""
        },
        "16": {
          "source": "var aes_keygen = function(p, s, f){",
          "coverage": 1
        },
        "17": {
          "source": "  if (!p.params.keysize) {",
          "coverage": ""
        },
        "18": {
          "source": "    f('no_params_keysize', {}, p);",
          "coverage": 0
        },
        "19": {
          "source": "    return;",
          "coverage": 0
        },
        "20": {
          "source": "  }",
          "coverage": ""
        },
        "21": {
          "source": "  if (p.params.algorithm.toLowerCase() !== \"aes\") {",
          "coverage": ""
        },
        "22": {
          "source": "    f('keygen_bad_algorithm', {}, p);",
          "coverage": 0
        },
        "23": {
          "source": "    return;",
          "coverage": 0
        },
        "24": {
          "source": "  }",
          "coverage": ""
        },
        "25": {
          "source": "  var keysize = parseInt(p.params.keysize, 10);",
          "coverage": 0
        },
        "26": {
          "source": "  //keysize is in bit, need to convert to bytes to generate random key",
          "coverage": ""
        },
        "27": {
          "source": "  //but the legacy code has a bug, it doesn't do the convert, so if the keysize is less than 100, don't convert",
          "coverage": ""
        },
        "28": {
          "source": "  if(keysize > 100){",
          "coverage": ""
        },
        "29": {
          "source": "    keysize = keysize/8;",
          "coverage": 0
        },
        "30": {
          "source": "  }",
          "coverage": ""
        },
        "31": {
          "source": "  if(typeof SecureRandom === \"undefined\"){",
          "coverage": ""
        },
        "32": {
          "source": "    return f(\"security library is not loaded.\");",
          "coverage": 0
        },
        "33": {
          "source": "  }",
          "coverage": ""
        },
        "34": {
          "source": "  return s({",
          "coverage": 0
        },
        "35": {
          "source": "    'algorithm': 'AES',",
          "coverage": ""
        },
        "36": {
          "source": "    'secretkey': generateRandomKey(keysize),",
          "coverage": ""
        },
        "37": {
          "source": "    'iv': generateRandomKey(keysize)",
          "coverage": ""
        },
        "38": {
          "source": "  });",
          "coverage": ""
        },
        "39": {
          "source": "};",
          "coverage": ""
        },
        "40": {
          "source": "",
          "coverage": ""
        },
        "41": {
          "source": "module.exports = aes_keygen;",
          "coverage": 1
        }
      }
    },
    {
      "filename": "src/modules/security/aes-node.js",
      "coverage": 20,
      "hits": 4,
      "misses": 16,
      "sloc": 20,
      "source": {
        "1": {
          "source": "var CryptoJS = require(\"../../../libs/generated/crypto\");",
          "coverage": 1
        },
        "2": {
          "source": "",
          "coverage": ""
        },
        "3": {
          "source": "var encrypt = function(p, s, f){",
          "coverage": 1
        },
        "4": {
          "source": "  var fields = ['key', 'plaintext', 'iv'];",
          "coverage": 0
        },
        "5": {
          "source": "  if(p.params.algorithm.toLowerCase() !== \"aes\"){",
          "coverage": ""
        },
        "6": {
          "source": "    return f('encrypt_bad_algorithm', {}, p);",
          "coverage": 0
        },
        "7": {
          "source": "  }",
          "coverage": ""
        },
        "8": {
          "source": "  for (var i = 0; i < fields; i++) {",
          "coverage": ""
        },
        "9": {
          "source": "    var field = fields[i];",
          "coverage": 0
        },
        "10": {
          "source": "    if (!p.params[field]) {",
          "coverage": ""
        },
        "11": {
          "source": "      return f('no_params_' + field, {}, p);",
          "coverage": 0
        },
        "12": {
          "source": "    }",
          "coverage": ""
        },
        "13": {
          "source": "  }",
          "coverage": ""
        },
        "14": {
          "source": "  var encrypted = CryptoJS.AES.encrypt(p.params.plaintext, CryptoJS.enc.Hex.parse(p.params.key), {iv: CryptoJS.enc.Hex.parse(p.params.iv)});",
          "coverage": 0
        },
        "15": {
          "source": "  cipher_text = CryptoJS.enc.Hex.stringify(encrypted.ciphertext);",
          "coverage": 0
        },
        "16": {
          "source": "  return s({ciphertext: cipher_text});",
          "coverage": 0
        },
        "17": {
          "source": "};",
          "coverage": ""
        },
        "18": {
          "source": "",
          "coverage": ""
        },
        "19": {
          "source": "var decrypt = function(p, s, f){",
          "coverage": 1
        },
        "20": {
          "source": "  var fields = ['key', 'ciphertext', 'iv'];",
          "coverage": 0
        },
        "21": {
          "source": "  if(p.params.algorithm.toLowerCase() !== \"aes\"){",
          "coverage": ""
        },
        "22": {
          "source": "    return f('decrypt_bad_algorithm', {}, p);",
          "coverage": 0
        },
        "23": {
          "source": "  }",
          "coverage": ""
        },
        "24": {
          "source": "  for (var i = 0; i < fields; i++) {",
          "coverage": ""
        },
        "25": {
          "source": "    var field = fields[i];",
          "coverage": 0
        },
        "26": {
          "source": "    if (!p.params[field]) {",
          "coverage": ""
        },
        "27": {
          "source": "      return f('no_params_' + field, {}, p);",
          "coverage": 0
        },
        "28": {
          "source": "    }",
          "coverage": ""
        },
        "29": {
          "source": "  }",
          "coverage": ""
        },
        "30": {
          "source": "  var data = CryptoJS.enc.Hex.parse(p.params.ciphertext);",
          "coverage": 0
        },
        "31": {
          "source": "  var encodeData = CryptoJS.enc.Base64.stringify(data);",
          "coverage": 0
        },
        "32": {
          "source": "  var decrypted = CryptoJS.AES.decrypt(encodeData, CryptoJS.enc.Hex.parse(p.params.key), {iv: CryptoJS.enc.Hex.parse(p.params.iv)});",
          "coverage": 0
        },
        "33": {
          "source": "  ",
          "coverage": ""
        },
        "34": {
          "source": "  try {",
          "coverage": ""
        },
        "35": {
          "source": "    return s({plaintext:decrypted.toString(CryptoJS.enc.Utf8)});",
          "coverage": 0
        },
        "36": {
          "source": "  } catch (e) {",
          "coverage": ""
        },
        "37": {
          "source": "    return f(e);",
          "coverage": 0
        },
        "38": {
          "source": "  }",
          "coverage": ""
        },
        "39": {
          "source": "};",
          "coverage": ""
        },
        "40": {
          "source": "",
          "coverage": ""
        },
        "41": {
          "source": "module.exports = {",
          "coverage": 1
        },
        "42": {
          "source": "  encrypt: encrypt,",
          "coverage": ""
        },
        "43": {
          "source": "  decrypt: decrypt",
          "coverage": ""
        },
        "44": {
          "source": "};",
          "coverage": ""
        },
        "45": {
          "source": "",
          "coverage": ""
        }
      }
    },
    {
      "filename": "src/modules/security/hash.js",
      "coverage": 25,
      "hits": 3,
      "misses": 9,
      "sloc": 12,
      "source": {
        "1": {
          "source": "var CryptoJS = require(\"../../../libs/generated/crypto\");",
          "coverage": 1
        },
        "2": {
          "source": "",
          "coverage": ""
        },
        "3": {
          "source": "",
          "coverage": ""
        },
        "4": {
          "source": "var hash = function(p, s, f){",
          "coverage": 1
        },
        "5": {
          "source": "  if (!p.params.text) {",
          "coverage": ""
        },
        "6": {
          "source": "    f('hash_no_text', {}, p);",
          "coverage": 0
        },
        "7": {
          "source": "    return;",
          "coverage": 0
        },
        "8": {
          "source": "  }",
          "coverage": ""
        },
        "9": {
          "source": "  var hashValue;",
          "coverage": 0
        },
        "10": {
          "source": "  if (p.params.algorithm.toLowerCase() === \"md5\") {",
          "coverage": ""
        },
        "11": {
          "source": "    hashValue = CryptoJS.MD5(p.params.text).toString(CryptoJS.enc.Hex);",
          "coverage": 0
        },
        "12": {
          "source": "  } else if(p.params.algorithm.toLowerCase() === \"sha1\"){",
          "coverage": ""
        },
        "13": {
          "source": "    hashValue = CryptoJS.SHA1(p.params.text).toString(CryptoJS.enc.Hex);",
          "coverage": 0
        },
        "14": {
          "source": "  } else if(p.params.algorithm.toLowerCase() === \"sha256\"){",
          "coverage": ""
        },
        "15": {
          "source": "    hashValue = CryptoJS.SHA256(p.params.text).toString(CryptoJS.enc.Hex);",
          "coverage": 0
        },
        "16": {
          "source": "  } else if(p.params.algorithm.toLowerCase() === \"sha512\"){",
          "coverage": ""
        },
        "17": {
          "source": "    hashValue = CryptoJS.SHA512(p.params.text).toString(CryptoJS.enc.Hex);",
          "coverage": 0
        },
        "18": {
          "source": "  } else {",
          "coverage": ""
        },
        "19": {
          "source": "    return f(\"hash_unsupported_algorithm: \" + p.params.algorithm);",
          "coverage": 0
        },
        "20": {
          "source": "  }",
          "coverage": ""
        },
        "21": {
          "source": "  return s({\"hashvalue\": hashValue});",
          "coverage": 0
        },
        "22": {
          "source": "};",
          "coverage": ""
        },
        "23": {
          "source": "",
          "coverage": ""
        },
        "24": {
          "source": "module.exports = hash;",
          "coverage": 1
        }
      }
    },
    {
      "filename": "src/modules/security/rsa-node.js",
      "coverage": 30.76923076923077,
      "hits": 4,
      "misses": 9,
      "sloc": 13,
      "source": {
        "1": {
          "source": "var rsa = require(\"../../../libs/rsa\");",
          "coverage": 1
        },
        "2": {
          "source": "var RSAKey = rsa.RSAKey;",
          "coverage": 1
        },
        "3": {
          "source": "",
          "coverage": ""
        },
        "4": {
          "source": "var encrypt = function(p, s, f){",
          "coverage": 1
        },
        "5": {
          "source": "  var fields = ['modulu', 'plaintext'];",
          "coverage": 0
        },
        "6": {
          "source": "  if(p.params.algorithm.toLowerCase() !== \"rsa\"){",
          "coverage": ""
        },
        "7": {
          "source": "    return f('encrypt_bad_algorithm', {}, p);",
          "coverage": 0
        },
        "8": {
          "source": "  }",
          "coverage": ""
        },
        "9": {
          "source": "  for (var i = 0; i < fields; i++) {",
          "coverage": ""
        },
        "10": {
          "source": "    var field = fields[i];",
          "coverage": 0
        },
        "11": {
          "source": "    if (!p.params[field]) {",
          "coverage": ""
        },
        "12": {
          "source": "      return f('no_params_' + field, {}, p);",
          "coverage": 0
        },
        "13": {
          "source": "    }",
          "coverage": ""
        },
        "14": {
          "source": "  }",
          "coverage": ""
        },
        "15": {
          "source": "  var key = new RSAKey();",
          "coverage": 0
        },
        "16": {
          "source": "  key.setPublic(p.params.modulu, \"10001\");",
          "coverage": 0
        },
        "17": {
          "source": "  var ori_text = p.params.plaintext;",
          "coverage": 0
        },
        "18": {
          "source": "  cipher_text = key.encrypt(ori_text);",
          "coverage": 0
        },
        "19": {
          "source": "  return s({ciphertext:cipher_text});",
          "coverage": 0
        },
        "20": {
          "source": "};",
          "coverage": ""
        },
        "21": {
          "source": "",
          "coverage": ""
        },
        "22": {
          "source": "module.exports = {",
          "coverage": 1
        },
        "23": {
          "source": "  encrypt: encrypt",
          "coverage": ""
        },
        "24": {
          "source": "};",
          "coverage": ""
        }
      }
    },
    {
      "filename": "src/modules/sync_cloud_handler.js",
      "coverage": 66.66666666666666,
      "hits": 2,
      "misses": 1,
      "sloc": 3,
      "source": {
        "1": {
          "source": "var cloudAPI = require(\"./api_cloud\");",
          "coverage": 1
        },
        "2": {
          "source": "",
          "coverage": ""
        },
        "3": {
          "source": "module.exports = function (params, success, failure) {",
          "coverage": 1
        },
        "4": {
          "source": "    cloudAPI({",
          "coverage": 0
        },
        "5": {
          "source": "        'path': '/mbaas/sync/' + params.dataset_id,",
          "coverage": ""
        },
        "6": {
          "source": "        'method': 'post',",
          "coverage": ""
        },
        "7": {
          "source": "        'data': params.req",
          "coverage": ""
        },
        "8": {
          "source": "    }, success, failure);",
          "coverage": ""
        },
        "9": {
          "source": "};",
          "coverage": ""
        }
      }
    },
    {
      "filename": "src/modules/uuid.js",
      "coverage": 12.5,
      "hits": 1,
      "misses": 7,
      "sloc": 8,
      "source": {
        "1": {
          "source": "module.exports = {",
          "coverage": 1
        },
        "2": {
          "source": "  createUUID : function () {",
          "coverage": ""
        },
        "3": {
          "source": "    //from http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript",
          "coverage": ""
        },
        "4": {
          "source": "    //based on RFC 4122, section 4.4 (Algorithms for creating UUID from truely random pr pseudo-random number)",
          "coverage": ""
        },
        "5": {
          "source": "    var s = [];",
          "coverage": 0
        },
        "6": {
          "source": "    var hexDigitals = \"0123456789ABCDEF\";",
          "coverage": 0
        },
        "7": {
          "source": "    for (var i = 0; i < 32; i++) {",
          "coverage": ""
        },
        "8": {
          "source": "      s[i] = hexDigitals.substr(Math.floor(Math.random() * 0x10), 1);",
          "coverage": 0
        },
        "9": {
          "source": "    }",
          "coverage": ""
        },
        "10": {
          "source": "    s[12] = \"4\";",
          "coverage": 0
        },
        "11": {
          "source": "    s[16] = hexDigitals.substr((s[16] & 0x3) | 0x8, 1);",
          "coverage": 0
        },
        "12": {
          "source": "    var uuid = s.join(\"\");",
          "coverage": 0
        },
        "13": {
          "source": "    return uuid;",
          "coverage": 0
        },
        "14": {
          "source": "  }",
          "coverage": ""
        },
        "15": {
          "source": "};",
          "coverage": ""
        },
        "16": {
          "source": "",
          "coverage": ""
        }
      }
    },
    {
      "filename": "src/modules/waitForCloud.js",
      "coverage": 72,
      "hits": 36,
      "misses": 14,
      "sloc": 50,
      "source": {
        "1": {
          "source": "var initializer = require(\"./initializer\");",
          "coverage": 1
        },
        "2": {
          "source": "var events = require(\"./events\");",
          "coverage": 1
        },
        "3": {
          "source": "var CloudHost = require(\"./hosts\");",
          "coverage": 1
        },
        "4": {
          "source": "var constants = require(\"./constants\");",
          "coverage": 1
        },
        "5": {
          "source": "var logger = require(\"./logger\");",
          "coverage": 1
        },
        "6": {
          "source": "var data = require('./data');",
          "coverage": 1
        },
        "7": {
          "source": "var fhparams = require('./fhparams');",
          "coverage": 1
        },
        "8": {
          "source": "",
          "coverage": ""
        },
        "9": {
          "source": "//the cloud configurations",
          "coverage": ""
        },
        "10": {
          "source": "var cloud_host;",
          "coverage": 1
        },
        "11": {
          "source": "",
          "coverage": ""
        },
        "12": {
          "source": "var is_initialising = false;",
          "coverage": 1
        },
        "13": {
          "source": "var is_cloud_ready = false;",
          "coverage": 1
        },
        "14": {
          "source": "var init_error = null;",
          "coverage": 1
        },
        "15": {
          "source": "",
          "coverage": ""
        },
        "16": {
          "source": "",
          "coverage": ""
        },
        "17": {
          "source": "var ready = function(cb){",
          "coverage": 1
        },
        "18": {
          "source": "  if(is_cloud_ready){",
          "coverage": ""
        },
        "19": {
          "source": "    return cb(null, {host: getCloudHostUrl()});",
          "coverage": 0
        },
        "20": {
          "source": "  } else {",
          "coverage": ""
        },
        "21": {
          "source": "    events.once(constants.INIT_EVENT, function(err, host){",
          "coverage": 1
        },
        "22": {
          "source": "      return cb(err, host);",
          "coverage": 1
        },
        "23": {
          "source": "    });",
          "coverage": ""
        },
        "24": {
          "source": "    if(!is_initialising){",
          "coverage": ""
        },
        "25": {
          "source": "      is_initialising = true;",
          "coverage": 1
        },
        "26": {
          "source": "      var fhinit = function(){",
          "coverage": 1
        },
        "27": {
          "source": "        data.sessionManager.read(function(err, session){",
          "coverage": 1
        },
        "28": {
          "source": "          //load the persisted sessionToken and set it for the session",
          "coverage": ""
        },
        "29": {
          "source": "          if(session && session.sessionToken){",
          "coverage": ""
        },
        "30": {
          "source": "            fhparams.setAuthSessionToken(session.sessionToken);",
          "coverage": 0
        },
        "31": {
          "source": "          }",
          "coverage": ""
        },
        "32": {
          "source": "          initializer.init(function(err, initRes){",
          "coverage": 1
        },
        "33": {
          "source": "            is_initialising = false;",
          "coverage": 1
        },
        "34": {
          "source": "            if(err){",
          "coverage": ""
        },
        "35": {
          "source": "              init_error = err;",
          "coverage": 0
        },
        "36": {
          "source": "              return events.emit(constants.INIT_EVENT, err);",
          "coverage": 0
        },
        "37": {
          "source": "            } else {",
          "coverage": ""
        },
        "38": {
          "source": "              init_error = null;",
          "coverage": 1
        },
        "39": {
          "source": "              is_cloud_ready = true;",
          "coverage": 1
        },
        "40": {
          "source": "              cloud_host = new CloudHost(initRes.cloud);",
          "coverage": 1
        },
        "41": {
          "source": "              return events.emit(constants.INIT_EVENT, null, {host: getCloudHostUrl()});",
          "coverage": 1
        },
        "42": {
          "source": "            }",
          "coverage": ""
        },
        "43": {
          "source": "          });",
          "coverage": ""
        },
        "44": {
          "source": "        });",
          "coverage": ""
        },
        "45": {
          "source": "      };",
          "coverage": ""
        },
        "46": {
          "source": "      if(typeof window.cordova !== \"undefined\" || typeof window.phonegap !== \"undefined\"){",
          "coverage": ""
        },
        "47": {
          "source": "        //if we are running inside cordova/phonegap, only init after device is ready to ensure the device id is the right one",
          "coverage": ""
        },
        "48": {
          "source": "        document.addEventListener(\"deviceready\", fhinit, false);",
          "coverage": 0
        },
        "49": {
          "source": "      } else {",
          "coverage": ""
        },
        "50": {
          "source": "        fhinit();",
          "coverage": 1
        },
        "51": {
          "source": "      }",
          "coverage": ""
        },
        "52": {
          "source": "    }",
          "coverage": ""
        },
        "53": {
          "source": "  }",
          "coverage": ""
        },
        "54": {
          "source": "};",
          "coverage": ""
        },
        "55": {
          "source": "",
          "coverage": ""
        },
        "56": {
          "source": "var getCloudHost = function(){",
          "coverage": 1
        },
        "57": {
          "source": "  return cloud_host;",
          "coverage": 0
        },
        "58": {
          "source": "};",
          "coverage": ""
        },
        "59": {
          "source": "",
          "coverage": ""
        },
        "60": {
          "source": "var getCloudHostUrl = function(){",
          "coverage": 1
        },
        "61": {
          "source": "  if(typeof cloud_host !== \"undefined\"){",
          "coverage": ""
        },
        "62": {
          "source": "    var appProps = require(\"./appProps\").getAppProps();",
          "coverage": 1
        },
        "63": {
          "source": "    return cloud_host.getHost(appProps.mode);",
          "coverage": 1
        },
        "64": {
          "source": "  } else {",
          "coverage": ""
        },
        "65": {
          "source": "    return undefined;",
          "coverage": 0
        },
        "66": {
          "source": "  }",
          "coverage": ""
        },
        "67": {
          "source": "};",
          "coverage": ""
        },
        "68": {
          "source": "",
          "coverage": ""
        },
        "69": {
          "source": "var isReady = function(){",
          "coverage": 1
        },
        "70": {
          "source": "  return is_cloud_ready;",
          "coverage": 1
        },
        "71": {
          "source": "};",
          "coverage": ""
        },
        "72": {
          "source": "",
          "coverage": ""
        },
        "73": {
          "source": "var getInitError = function(){",
          "coverage": 1
        },
        "74": {
          "source": "  return init_error;",
          "coverage": 1
        },
        "75": {
          "source": "};",
          "coverage": ""
        },
        "76": {
          "source": "",
          "coverage": ""
        },
        "77": {
          "source": "//for test",
          "coverage": ""
        },
        "78": {
          "source": "var reset = function(){",
          "coverage": 1
        },
        "79": {
          "source": "  is_cloud_ready = false;",
          "coverage": 0
        },
        "80": {
          "source": "  is_initialising = false;",
          "coverage": 0
        },
        "81": {
          "source": "  cloud_host = undefined;",
          "coverage": 0
        },
        "82": {
          "source": "  init_error = undefined;",
          "coverage": 0
        },
        "83": {
          "source": "  ready(function(){",
          "coverage": 0
        },
        "84": {
          "source": "    ",
          "coverage": ""
        },
        "85": {
          "source": "  });",
          "coverage": ""
        },
        "86": {
          "source": "};",
          "coverage": ""
        },
        "87": {
          "source": "",
          "coverage": ""
        },
        "88": {
          "source": "ready(function(error, host){",
          "coverage": 1
        },
        "89": {
          "source": "  if(error){",
          "coverage": ""
        },
        "90": {
          "source": "    if(error.message !== \"app_config_missing\"){",
          "coverage": ""
        },
        "91": {
          "source": "      logger.error(\"Failed to initialise fh.\");",
          "coverage": 0
        },
        "92": {
          "source": "    } else {",
          "coverage": ""
        },
        "93": {
          "source": "      logger.info(\"No fh config file\");",
          "coverage": 0
        },
        "94": {
          "source": "    }",
          "coverage": ""
        },
        "95": {
          "source": "  } else {",
          "coverage": ""
        },
        "96": {
          "source": "    logger.info(\"fh cloud is ready\");",
          "coverage": 1
        },
        "97": {
          "source": "  }",
          "coverage": ""
        },
        "98": {
          "source": "});",
          "coverage": ""
        },
        "99": {
          "source": "",
          "coverage": ""
        },
        "100": {
          "source": "module.exports = {",
          "coverage": 1
        },
        "101": {
          "source": "  ready: ready,",
          "coverage": ""
        },
        "102": {
          "source": "  isReady: isReady,",
          "coverage": ""
        },
        "103": {
          "source": "  getCloudHost: getCloudHost,",
          "coverage": ""
        },
        "104": {
          "source": "  getCloudHostUrl: getCloudHostUrl,",
          "coverage": ""
        },
        "105": {
          "source": "  getInitError: getInitError,",
          "coverage": ""
        },
        "106": {
          "source": "  reset: reset",
          "coverage": ""
        },
        "107": {
          "source": "};",
          "coverage": ""
        }
      }
    }
  ],
  "stats": {
    "suites": 13,
    "tests": 18,
    "passes": 18,
    "pending": 0,
    "failures": 0,
    "start": "2017-08-15T16:07:30.106Z",
    "end": "2017-08-15T16:07:30.854Z",
    "duration": 748
  },
  "tests": [
    {
      "title": "load initial dataset from remote",
      "fullTitle": "test sync framework cloud handler load initial dataset from remote",
      "duration": 622
    },
    {
      "title": "should call the success callback",
      "fullTitle": "test ajax module should call the success callback",
      "duration": 20
    },
    {
      "title": "should call the error callback",
      "fullTitle": "test ajax module should call the error callback",
      "duration": 2
    },
    {
      "title": "AES keygen",
      "fullTitle": "test security APIs AES keygen",
      "duration": 1
    },
    {
      "title": "AES encrypt/decrypt",
      "fullTitle": "test security APIs AES encrypt/decrypt",
      "duration": 2
    },
    {
      "title": "RSA encrypt",
      "fullTitle": "test security APIs RSA encrypt",
      "duration": 19
    },
    {
      "title": "hash",
      "fullTitle": "test security APIs hash",
      "duration": 7
    },
    {
      "title": "should emit fhinit events",
      "fullTitle": "test all cloud related test auto initialisation should emit fhinit events",
      "duration": 2
    },
    {
      "title": "act call should success",
      "fullTitle": "test all cloud related test act/cloud call act call should success",
      "duration": 11
    },
    {
      "title": "should work with cloud call",
      "fullTitle": "test all cloud related test act/cloud call should work with cloud call",
      "duration": 2
    },
    {
      "title": "auth call should work",
      "fullTitle": "test all cloud related test auth call auth call should work",
      "duration": 10
    },
    {
      "title": "mbaas call should call",
      "fullTitle": "test all cloud related test mbaas call mbaas call should call",
      "duration": 3
    },
    {
      "title": "should work with cloud GET call",
      "fullTitle": "test all cloud related GETs should work with cloud GET call",
      "duration": 10
    },
    {
      "title": "$fh.init should initialise the app",
      "fullTitle": "test legacy app props/app init test legacy app init $fh.init should initialise the app",
      "duration": 3
    },
    {
      "title": "should emit fhinit events",
      "fullTitle": "test legacy app props/app init test auto initialisation should emit fhinit events",
      "duration": 0
    },
    {
      "title": "should invoke wrapped push",
      "fullTitle": "test push wrapper should invoke wrapped push",
      "duration": 1
    },
    {
      "title": "should invoke fail when push plugin is not installed",
      "fullTitle": "test push wrapper should invoke fail when push plugin is not installed",
      "duration": 5
    },
    {
      "title": "should append config to the appConfig",
      "fullTitle": "test push wrapper should append config to the appConfig",
      "duration": 8
    }
  ],
  "failures": [],
  "passes": [
    {
      "title": "load initial dataset from remote",
      "fullTitle": "test sync framework cloud handler load initial dataset from remote",
      "duration": 622
    },
    {
      "title": "should call the success callback",
      "fullTitle": "test ajax module should call the success callback",
      "duration": 20
    },
    {
      "title": "should call the error callback",
      "fullTitle": "test ajax module should call the error callback",
      "duration": 2
    },
    {
      "title": "AES keygen",
      "fullTitle": "test security APIs AES keygen",
      "duration": 1
    },
    {
      "title": "AES encrypt/decrypt",
      "fullTitle": "test security APIs AES encrypt/decrypt",
      "duration": 2
    },
    {
      "title": "RSA encrypt",
      "fullTitle": "test security APIs RSA encrypt",
      "duration": 19
    },
    {
      "title": "hash",
      "fullTitle": "test security APIs hash",
      "duration": 7
    },
    {
      "title": "should emit fhinit events",
      "fullTitle": "test all cloud related test auto initialisation should emit fhinit events",
      "duration": 2
    },
    {
      "title": "act call should success",
      "fullTitle": "test all cloud related test act/cloud call act call should success",
      "duration": 11
    },
    {
      "title": "should work with cloud call",
      "fullTitle": "test all cloud related test act/cloud call should work with cloud call",
      "duration": 2
    },
    {
      "title": "auth call should work",
      "fullTitle": "test all cloud related test auth call auth call should work",
      "duration": 10
    },
    {
      "title": "mbaas call should call",
      "fullTitle": "test all cloud related test mbaas call mbaas call should call",
      "duration": 3
    },
    {
      "title": "should work with cloud GET call",
      "fullTitle": "test all cloud related GETs should work with cloud GET call",
      "duration": 10
    },
    {
      "title": "$fh.init should initialise the app",
      "fullTitle": "test legacy app props/app init test legacy app init $fh.init should initialise the app",
      "duration": 3
    },
    {
      "title": "should emit fhinit events",
      "fullTitle": "test legacy app props/app init test auto initialisation should emit fhinit events",
      "duration": 0
    },
    {
      "title": "should invoke wrapped push",
      "fullTitle": "test push wrapper should invoke wrapped push",
      "duration": 1
    },
    {
      "title": "should invoke fail when push plugin is not installed",
      "fullTitle": "test push wrapper should invoke fail when push plugin is not installed",
      "duration": 5
    },
    {
      "title": "should append config to the appConfig",
      "fullTitle": "test push wrapper should append config to the appConfig",
      "duration": 8
    }
  ]
}