API Docs for: 0.0.3
Show:

File: lib/cda.js

/*
 * Copyright 2013 Joel latino
 * Contact: jlatino@sapo.pt ~ http://about.me/latinojoel/ ~ http://latinojoel.github.io/cdajs ~ http://joel-latino.blogspot.com
 * Twitter: @latinojoel
 *
 * Include this in your web-pages for debug and development purposes only. For production purposes,
 * consider using the minified/obfuscated versions in the /min directory.
 *
 * This program is free software: you can redistribute it and/or modify it under the terms of the
 * GNU Lesser General Public License as published by the Free Software Foundation,
 * either version 3 of the License, or (at your option) any later version. This
 * program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
 * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
 * Public License for more details. You should have received a copy of the GNU General Public
 * License along with this program.
 * If not, see <http://www.gnu.org/licenses/>.
 */

"use strict"; // js-hint is fuck'd up ^^

/**
 * This is <b>CDAjs</b> - a stand-alone javascript library for working with Pentaho plugin
 * "Community Data Access" CDA (<i>Community Data Access</i>) is a open source plugin for
 * <b>Pentaho Business Analysis</b> suite, designed to allow greater flexibility for data sources.
 * Powered by <a href="http://www.webdetails.pt/ctools/cda.html" target="_blank">WebDetails</a>.
 * <br/><br/> <b>CDAjs</b> is cross-browser and <a href="http://nodejs.org"target="_blank">Node.js</a>
 * compatible and enables web-browser-based analytical Pentaho Business Intelligence applications.
 *
 * @module CDAjs
 * @title CDAjs
 */
 (function (window) {


  /**
   * Get's a XML Http Request
   *
   * @return {Object} a XML Http Request object.
   */

   function _Xhr() {
    if (window.XMLHttpRequest) {
      return new window.XMLHttpRequest();
    } else if (window.ActiveXObject) {
      return new window.ActiveXObject("MSXML2.XMLHTTP.3.0");
    } else if (typeof (require) === "function") {
      var xhr;
      (xhr = function () {
        this.readyState = 0;
        this.status = -1;
        this.statusText = "Not sent";
        this.responseText = null;
      }).prototype = {
        changeStatus: function (statusCode, readyState) {
          this.status = statusCode;
          this.statusText = statusCode;
          this.readyState = readyState;
          if (_isFun(this.onreadystatechange)) {
            this.onreadystatechange.call(this, this);
          }
        },
        open: function (method, url, async, username, password) {
          if (async !== true) {
            throw "Synchronous mode not supported in this environment.";
          }
          var options = require("url").parse(url);
          if (options.host.length > options.hostname.length) {
            // for some reason, host includes the port, this confuses http.request
            // so, overwrite host with hostname (which does not include the port)
            // and kill hostname so that we end up with only host.
            options.host = options.hostname;
            delete options.hostname;
          }
          if (!options.path && options.pathname) {
            // old versions of node may not give the path, so we need to create it ourselves.
            options.path = options.pathname + (options.search || "");
          }
          options.method = CDA.DEFAULT_OPTIONS.METHOD; // method;
          options.headers = {};
          if (username) options.headers.Authorization = "Basic " + (new Buffer(username + ":" + (password || ""))).toString("base64");
          this.options = options;
          this.changeStatus(-1, 1);
        },
        send: function (data) {
          var me = this,
          options = me.options,
          client;
          if (data) {
            options.headers["Content-Length"] = Buffer.byteLength(data);
          }
          switch (options.protocol) {
            case "http:":
            client = require("http");
            if (!options.port) options.port = "80";
            break;
            case "https:":
            client = require("https");
            if (!options.port) options.port = "443";
            break;
            default:
            throw "Unsupported protocol " + options.protocol;
          }
          me.responseText = "";
          var request = client.request(options, function (response) {
            response.setEncoding("utf8");
            me.changeStatus(-1, 2);
            response.on("data", function (chunk) {
              me.responseText += chunk;
              me.changeStatus(response.statusCode, 3);
            });
            response.on("error", function (error) {
              me.changeStatus(response.statusCode, 4);
            });
            response.on("end", function () {
              me.changeStatus(response.statusCode, 4);
            });
          });
          request.on("error", function (e) {
            me.responseText = e;
            me.changeStatus(500, 4);
          });
          if (data) request.write(data);
          request.end();
        },
        setRequestHeader: function (name, value) {
          this.options.headers[name] = value;
        }
      };
      return new xhr();
    } else {
      CDA.Exception.newError("ERROR_INSTANTIATING_XMLHTTPREQUEST", "ajax", null)._throw();
    }
  }


  /**
   * Convert parameters for HTTP request.
   *
   * @param params a parameters to convert.
   * @return {string} a string with parameters converted for HTTP request.
   */

   function _convertParams(params) {
    var form = "?";
    var isFirst = true;
    for (var key in params) {
      isFirst ? isFirst = false : form += "&";
      var value = typeof params[key] == 'function' ? params[key]() : params[key];
      form += key + "=" + value;
    }
    return form;
  }


  /**
   * Checks argument is undefined.
   *
   * @param arg an argument.
   * @return {boolean} <code>true</code> if argument is undefined, <code>false</code> if
   *         argument isn't undefined.
   */

   function _isUnd(arg) {
    return typeof (arg) === "undefined";
  }


  /**
   * Checks argument is function.
   *
   * @param arg an argument.
   * @return {boolean} <code>true</code> if argument is function, <code>false</code> if argument
   *         isn't function.
   */

   function _isFun(arg) {
    return typeof (arg) === "function";
  }


  /**
   * Function responsable for invoke an endpoint.
   *
   * @param callback a callback function executed when HTTP request to endpoint gives success.
   * @param options a options for invoke endpoint (can be HTTP parameters, ...).
   * @param endpoint an endpoint name.
   * @param self a self instance of CDAjs.
   */

   function _invokeEndpoint(callback, options, endpoint, self) {
    var xhr = _Xhr();
    options.method = options.method || CDA.DEFAULT_OPTIONS.METHOD;

    // Parameters for Pentaho Authentication
    if((options.username || self.options.username) !== undefined && (options.password || self.options.password) !== undefined){
      options.params["userid"] = options.username || self.options.username;
      options.params["password"] = options.password || self.options.password;
    }

    if(Object.getOwnPropertyNames(options.params).length>0){
      options.form = _convertParams(options.params);
    }

    var finalUrl = (options.url || self.options.url) + endpoint + (options.method.toUpperCase() === "GET" ? (options.form || "") : "");
    xhr.open(options.method, finalUrl, options.async || CDA.DEFAULT_OPTIONS.ASYNC, options.username, options.password);
    xhr.timeout = options.timeout || CDA.DEFAULT_OPTIONS.REQUEST_TIMEOUT;
    xhr.setRequestHeader("Accept", options["Accept"] || CDA.DEFAULT_OPTIONS.ACCEPT);
    xhr.setRequestHeader("Content-Type", options["Content-Type"] || CDA.DEFAULT_OPTIONS.CONTENT_TYPE);

    if (options.method.toUpperCase() === "GET") {
      xhr.send();
    } else {
      xhr.send(options.form || "");
    }

    xhr.onreadystatechange = function () {
      switch (xhr.readyState) {
        case 0:
        if (_isFun(options.aborted)) {
          options.aborted(xhr);
        }
        break;
        case 4:
        if (xhr.status === 200) {
          var response = "";
          try {
            response = JSON.parse(xhr.responseText);
          } catch (e) {
            response = xhr.responseText;
            console.log("Can not convert to JSON after invoke " + endpoint + " endpoint.");
          }
          callback(xhr.responseText == "" ? "" : response);
        } else {
          var err = CDA.Exception.newError("HTTP_ERROR", "xhr", {
            request: options,
            status: self.status,
            statusText: self.statusText
          });
          console.log("Error: " + err);
          // When I have an error in HTTP, this allows better debugging
          // So made an extra call instead of _newError inside func call
          if (!_isUnd(options.error) && _isFun(options.error)) {
            options.error(err);
          }
        }
        break;
      }
    };
  }


  if (!window.JSON) {
    window.JSON = {
      parse: function (sJSON) {
        return eval("(" + sJSON + ")");
      },
      stringify: function (vContent) {
        if (vContent instanceof Object) {
          var sOutput = "";
          if (vContent.constructor === Array) {
            for (var nId = 0; nId < vContent.length; sOutput += this.stringify(vContent[nId]) + ",", nId++);
              return "[" + sOutput.substr(0, sOutput.length - 1) + "]";
          }
          if (vContent.toString !== Object.prototype.toString) {
            return "\"" + vContent.toString().replace(/"/g, "\\$&") + "\"";
          }
          for (var sProp in vContent) {
            sOutput += "\"" + sProp.replace(/"/g, "\\$&") + "\":" + this.stringify(vContent[sProp]) + ",";
          }
          return "{" + sOutput.substr(0, sOutput.length - 1) + "}";
        }
        return typeof vContent === "string" ? "\"" + vContent.replace(/"/g, "\\$&") + "\"" : String(vContent);
      }
    };
  }


  /**
   * The CDA class provides a javascript API to communicate Pentaho Community Data Access plugin
   * (CDA) over HTTP.
   *
   * @class CDA
   * @constructor
   * @param options {Object} standard options
   */

   function CDA(options) {
    this.options = options || CDA.Exception.newError("ERROR_CDA_OPTIONS", "CDA.constructor", null)._throw();
    this.options.url = options.url || CDA.Exception.newError("ERROR_CDA_URL", "CDA.constructor", null)._throw();
    if(typeof exports === "undefined"){
      this.options.username = options.username;
      this.options.password = options.password;
    }else{
      this.options.username = options.username || CDA.Exception.newError("ERROR_CDA_USERNAME", "CDA.constructor", null)._throw();
      this.options.password = options.password || CDA.Exception.newError("ERROR_CDA_PASSWORD", "CDA.constructor", null)._throw();
    }
    this.options.params = options.params || {};
  }


  /**
   * These are the default options used for new CDA instances in case no custom properties are set.
   * It sets the following properties:
   * <ul>
   * <li><code>REQUEST_TIMEOUT</code> int: 60000 - number of milliseconds before a request to the
   * Pentaho server will timeout </li>
   * <li><code>ASYNC</code> boolean: true - determines whether synchronous or asynchronous
   * communication with the Pentaho server will be used.</li>
   * <li><code>ACCEPT</code> string: text/xml, application/json - determines the accept header on
   * http request with the Pentaho server will be used.</li>
   * <li><code>CONTENT_TYPE</code> string: application/json - determines the content-type header
   * on http request with the Pentaho server will be used.</li>
   * <li><code>METHOD</code> string: GET - determines the method on http request with the Pentaho
   * server will be used.</li>
   * </ul>
   *
   * @property DEFAULT_OPTIONS
   * @static
   * @type object
   */
   CDA.DEFAULT_OPTIONS = {
    REQUEST_TIMEOUT: 60000,
    ASYNC: true,
    ACCEPT: "text/xml, application/json",
    CONTENT_TYPE: "application/json",
    METHOD: "GET"
  };

  /**
   * Invokes the <code>/cda/doQuery</code> endpoint of CDA.
   *
   * @method doQuery
   * @param {function()} callback Function to be called for cda query done.
   * @param {Object} options Options to use on http request.
   */
   CDA.prototype.doQuery = function (callback, options) {
    var endpoint = "doQuery";
    if (_isUnd(options)) {
      options = this.options;
    }
    // Is mandatory use dataAccessId
    if (_isUnd(options.params) || _isUnd(options.params.dataAccessId)) {
      CDA.Exception.newError("ERROR_MISSING_DATA_ACCESS_ID", endpoint, null)._throw();
    }

    // invokes endpoint
    _invokeEndpoint(callback, options, endpoint, this);
  };


  /**
   * Invokes the <code>/cda/listQueries</code> endpoint of CDA.
   *
   * @method listQueries
   * @param {function()} callback Function to be called for cda query done.
   * @param {Object} options Options to use on http request.
   */
   CDA.prototype.listQueries = function (callback, options) {
    var endpoint = "listQueries";
    if (_isUnd(options)) {
      options = this.options;
    }
    // Is mandatory use params
    if (_isUnd(options.params)) {
      CDA.Exception.newError("ERROR_MISSING_PARAMS", endpoint, null)._throw();
    }
    // Is mandatory use param path
    if (_isUnd(options.params.path)) {
      CDA.Exception.newError("ERROR_MISSING_PARAMS_PATH", endpoint, null)._throw();
    }

    // invokes endpoint
    _invokeEndpoint(callback, options, endpoint, this);
  };


  /**
   * Invokes the <code>/cda/getCdaList</code> endpoint of CDA.
   *
   * @method getCdaList
   * @param {function()} callback Function to be called for cda query done.
   * @param {Object} options Options to use on http request.
   */
   CDA.prototype.getCdaList = function (callback, options) {
    var endpoint = "getCdaList";
    if (_isUnd(options)) {
      options = this.options;
    }

    // invokes endpoint
    _invokeEndpoint(callback, options, endpoint, this);
  };


  /**
   * Invokes the <code>/cda/listDataAccessTypes</code> endpoint of CDA.
   *
   * @method listDataAccessTypes
   * @param {function()} callback Function to be called for cda query done.
   * @param {Object} options Options to use on http request.
   */
   CDA.prototype.listDataAccessTypes = function (callback, options) {
    var endpoint = "listDataAccessTypes";
    if (_isUnd(options)) {
      options = this.options;
    }

    // invokes endpoint
    _invokeEndpoint(callback, options, endpoint, this);
  };


  /**
   * Invokes the <code>/cda/listParameters</code> endpoint of CDA.
   *
   * @method listParameters
   * @param {function()} callback Function to be called for cda query done.
   * @param {Object} options Options to use on http request.
   */
   CDA.prototype.listParameters = function (callback, options) {
    var endpoint = "listParameters";
    if (_isUnd(options)) {
      options = this.options;
    }
    // Is mandatory use params
    if (_isUnd(options.params)) {
      CDA.Exception.newError("ERROR_MISSING_PARAMS", endpoint, null)._throw();
    }
    // Is mandatory use param path
    if (_isUnd(options.params.path)) {
      CDA.Exception.newError("ERROR_MISSING_PARAMS_PATH", endpoint, null)._throw();
    }
    // Is mandatory use param dataAccessId
    if (_isUnd(options.params.dataAccessId)) {
      CDA.Exception.newError("ERROR_MISSING_PARAMS_DATA_ACCESS_ID", endpoint, null)._throw();
    }

    // invokes endpoint
    _invokeEndpoint(callback, options, endpoint, this);
  };


  /**
   * Invokes the <code>/cda/clearCache</code> endpoint of CDA.
   *
   * @method clearCache
   * @param {function()} callback Function to be called for cda query done.
   * @param {Object} options Options to use on http request.
   */
   CDA.prototype.clearCache = function (callback, options) {
    var endpoint = "clearCache";
    if (_isUnd(options)) {
      options = this.options;
    }

    // invokes endpoint
    _invokeEndpoint(callback, options, endpoint, this);
  };


  /**
   * Invokes the <code>/cda/getCdaFile</code> endpoint of CDA.
   *
   * @method getCdaFile
   * @param {function()} callback Function to be called for cda query done.
   * @param {Object} options Options to use on http request.
   */
   CDA.prototype.getCdaFile = function (callback, options) {
    var endpoint = "getCdaFile";
    if (_isUnd(options)) {
      options = this.options;
    }

    // invokes endpoint
    _invokeEndpoint(callback, options, endpoint, this);
  };


  /**
   * <p>
   * This class is used to indicate an runtime errors occurring in any of the methods of the CDAjs
   * classes.
   * </p>
   * <p>
   * You do not need to instantiate objects of this class yourself. Rather, instances of this class
   * are created and thrown at runtime whenever an error occurs.
   * </p>
   * <p>
   * To handle CDAjs errors, you can use a <code>try...catch</code> block like this:
   * </p>
   *
   * <pre>
   *    try {
   *        ...general cdajs work...
   *    } catch (exception) {
   *        if (exception instanceof CDA.Exception) {
   *            ...use exception.code, exception.message and exception.data to handle the exception.
   *        } else {
   *            ...handle other errors...
   *        }
   *    }
   * </pre>
   *
   * @class CDA.Exception
   * @constructor
   */
   CDA.Exception = function (type, code, message, helpfile, source, data, args) {
    this.type = type;
    this.code = code;
    this.message = message;
    this.source = source;
    this.helpfile = helpfile;
    this.data = data;
    this.args = args;
    return this;
  };


  /**
   * Create an exception.
   *
   * @param codeName an exception code name.
   * @param source an exception source
   * @param data an exception data to specify
   * @return {Object|CDA.Exception}
   */
   CDA.Exception.newError = function (codeName, source, data) {
    return new this.newDetailError(CDA.Exception[codeName + "_CODE"], CDA.Exception[codeName + "_MSG"], CDA.Exception[codeName + "_HELP"], source, data);
  };


  /**
   * Create an exception.
   *
   * @param code an exception code name.
   * @param message an exception message.
   * @param help an exception information help.
   * @param source an exception source
   * @param data an exception data to specify
   * @returns {Object|CDA.Exception}
   */
   CDA.Exception.newDetailError = function (code, message, help, source, data) {
    return new CDA.Exception(CDA.Exception.TYPE_ERROR, code, message, help, source, data);
  };


  var CDAWikiExceptionCodes = "https://github.com/latinojoel/cdajs/wiki/Exception-Codes";


  /**
   * Can appear as value for the type property of instances of the CDA.Exception class, and
   * indicates that this <code>CDA.Exception</code> signals an error.
   *
   * @property TYPE_ERROR
   * @static
   * @final
   * @type string
   * @default error
   */
   CDA.Exception.TYPE_ERROR = "error";


  /**
   * Can appear as value for the type property of instances of the CDA.Exception class, and
   * indicates that this <code>CDA.Exception</code> signals a warning.
   *
   * @property TYPE_WARNING
   * @static
   * @final
   * @type string
   * @default warning
   */
   CDA.Exception.TYPE_WARNING = "warning";


  /**
   * Exception code indicating that missing the CDA URL.
   *
   * @property ERROR_CDA_URL_CODE
   * @static
   * @final
   * @type {int}
   * @default -1
   */
   CDA.Exception.ERROR_CDA_URL_CODE = -1;
   CDA.Exception.ERROR_CDA_URL_MSG = "Missing CDA URL";
   CDA.Exception.ERROR_CDA_URL_HELP = "Please provide CDA url on the CDA object constructor (Please consult this page " + CDAWikiExceptionCodes + ")";


  /**
   * Exception code indicating that missing options in the constructor.
   *
   * @property ERROR_CDA_OPTIONS_CODE
   * @static
   * @final
   * @type {int}
   * @default -2
   */
   CDA.Exception.ERROR_CDA_OPTIONS_CODE = -2;
   CDA.Exception.ERROR_CDA_OPTIONS_MSG = "Missing CDA Options";
   CDA.Exception.ERROR_CDA_OPTIONS_HELP = "Please provide CDA options on the CDA object constructor (Please consult this page " + CDAWikiExceptionCodes + ")";


  /**
   * Exception code indicating a general XMLHttpRequest error. If this error occurs, the data object
   * of the exception will have these members:
   * <ul>
   * <li>request: the options that make up the original HTTP request</li>
   * <li>status: the HTTP status code</li>
   * <li>statusText: the HTTP status text</li>
   * </ul>
   *
   * @property HTTP_ERROR_CODE
   * @static
   * @final
   * @type {int}
   * @default -3
   */
   CDA.Exception.HTTP_ERROR_CODE = -3;
   CDA.Exception.HTTP_ERROR_MSG = "HTTP ERROR";
   CDA.Exception.HTTP_ERROR_HELP = "Generic HTTP error (Please consult this page " + CDAWikiExceptionCodes + ")";


  /**
   * Exception code indicating that missing username for Pentaho authentication.
   *
   * @property ERROR_CDA_USERNAME_CODE
   * @static
   * @final
   * @type {int}
   * @default -4
   */
   CDA.Exception.ERROR_CDA_USERNAME_CODE = -4;
   CDA.Exception.ERROR_CDA_USERNAME_MSG = "Missing CDA Username";
   CDA.Exception.ERROR_CDA_USERNAME_HELP = "Please provide CDA username on the CDA object constructor (Please consult this page " + CDAWikiExceptionCodes + ")";


  /**
   * Exception code indicating that missing password for Pentaho authentication.
   *
   * @property ERROR_CDA_PASSWORD_CODE
   * @static
   * @final
   * @type {int}
   * @default -5
   */
   CDA.Exception.ERROR_CDA_PASSWORD_CODE = -5;
   CDA.Exception.ERROR_CDA_PASSWORD_MSG = "Missing CDA Password";
   CDA.Exception.ERROR_CDA_PASSWORD_HELP = "Please provide CDA password on the CDA object constructor (Please consult this page " + CDAWikiExceptionCodes + ")";


  /**
   * Exception code indicating that missing data access id for CDA query.
   *
   * @property ERROR_MISSING_DATA_ACCESS_ID_CODE
   * @static
   * @final
   * @type {int}
   * @default -6
   */
   CDA.Exception.ERROR_MISSING_DATA_ACCESS_ID_CODE = -6;
   CDA.Exception.ERROR_MISSING_DATA_ACCESS_ID_MSG = "Missing CDA data access id";
   CDA.Exception.ERROR_MISSING_DATA_ACCESS_ID_HELP = "Please provide CDA data access id (Please consult this page " + CDAWikiExceptionCodes + ")";


  /**
   * Exception code indicating that missing params object for invoke CDA endpoint.
   *
   * @property ERROR_MISSING_PARAMS_CODE
   * @static
   * @final
   * @type {int}
   * @default -7
   */
   CDA.Exception.ERROR_MISSING_PARAMS_CODE = -7;
   CDA.Exception.ERROR_MISSING_PARAMS_MSG = "Missing object params";
   CDA.Exception.ERROR_MISSING_PARAMS_HELP = "Please provide params (Please consult this page " + CDAWikiExceptionCodes + ")";


  /**
   * Exception code indicating that missing path property on object params for invoke CDA endpoint.
   *
   * @property ERROR_MISSING_PARAMS_PATH_CODE
   * @static
   * @final
   * @type {int}
   * @default -9
   */
   CDA.Exception.ERROR_MISSING_PARAMS_PATH_CODE = -9;
   CDA.Exception.ERROR_MISSING_PARAMS_PATH_MSG = "Missing path property on object params";
   CDA.Exception.ERROR_MISSING_PARAMS_PATH_HELP = "Please provide path property on params (Please consult this page " + CDAWikiExceptionCodes + ")";


   CDA.Exception.prototype = {

    /**
     * This propery indicates what kind of exception occurred. It can have one of the following
     * values:
     * <dl>
     * <dt><code>TYPE_WARNING</code></dt>
     * <dd>Indicates a warning</dd>
     * <dt><code>TYPE_ERROR</code></dt>
     * <dd>Indicates an error</dd>
     * </dl>
     *
     * @property type
     * @type {string}
     * @default null
     */
     type: null,


    /**
     * A code that can be used to identify this particular kind of exception.
     *
     * @property code
     * @type {int}
     * @default null
     */
     code: null,
    /**
     * A human readable message that describes the nature of the error or warning.
     *
     * @property message
     * @type {string}
     * @default null
     */
     message: null,


    /**
     * A name that indicates in what component (on the client or server side) this error or warning
     * occurred.
     *
     * @property source
     * @type {string}
     * @default null
     */
     source: null,


    /**
     * A path or url that points to a document that contains more information about this error.
     *
     * @property helpfile
     * @type {string}
     * @default null
     */
     helpfile: null,


    /**
     * Additional data captured when the exception was instantiated. The type of information stored
     * here is dependent upon the nature of the error.
     *
     * @property data
     * @type {string}
     * @default null
     */
     data: null,
     _throw: function () {
      throw this;
    },


    /**
     * A reference to the built-in <code>arguments</code> array of the function that is throwing
     * the exception This can be used to get a "stack trace"
     *
     * @property args
     * @type {array}
     */
     args: null,


    /**
     * Returns a string representing this exception
     *
     * @method toString
     * @return a string representing this exception
     */
     toString: function () {
      return this.type + " " + this.code + ": " + this.message + " (source: " + this.source + ")";
    },


    /**
     * Get a stack trace.
     *
     * @method getStackTrace
     * @return an array of objects describing the function on the stack
     */
     getStackTrace: function () {
      var stack = "";
      if (this.args) {
        var func = this.args.callee;
        while (func) {
          funcstring = String(func);
          func = func.caller;
        }
      }
      return stack;
    }
  };


  /*
   * Register CDAjs. In an amd (https://github.com/amdjs/amdjs-api/wiki/AMD) environment, use the
   * define function Otherwise, add it to the global window variable. For server side environemnts
   * that do not have a proper window object, simply create a global variable called window and
   * assign an object to it that you want to function as the CDA container.
   */
   if (typeof (define) === "function" && define.amd) {
    define(function () {
      return CDA;
    });
  } else window.CDA = CDA;

  return CDA;

})(typeof exports === "undefined" ? window : exports);