# Source: bemap.js

    /**
     * BeNomad BeMap JavaScript API
     * @projectname BeNomad BeMap JavaScript API
     */

    var bemap = bemap || {};

    bemap.version = '1.0.0';

    /**
     * Extends the class declaration with the parent class.
     * @param {Class} child
     * @param {Class} parent
     */
    bemap.inherits = function(child, parent) {
      child.prototype = Object.create(parent.prototype);
      child.prototype.constructor = child;
    };

    /**
     * Test if the object is inherits of the class (type).
     * @param {Object} obj The object.
     * @param {Class} type The inherits class model.
     * @return {boolean}
     */
    bemap.inheritsof = function(obj, type) {
      // return obj.prototype.isPrototypeOf(type);
      return (obj instanceof type);
    };

    /**
     * Fill all fields of target object with source object.
     * Only the feilds of target class model are filled.
     * @param {Object} source Source object.
     * @param {Object} target Target object.
     */
    bemap.fillFields = function(source, target) {
      for (var key in target) {
        var value = source[key];
        if (value) {
          target[key] = value;
        }
      }
    };

    /**
     * Get absolute path of current script.
     * @return {String} Retun absolute path of current script.
     */
    bemap._getCurrentPath_cache = null;
    bemap.getCurrentPath = function() {
      if (bemap._getCurrentPath_cache === null) {
        var scripts = document.getElementsByTagName('script');
        var path = scripts[scripts.length - 1].src.split('?')[0];
        bemap._getCurrentPath_cache = path.split('/').slice(0, -1).join('/') + '/';
      }
      return bemap._getCurrentPath_cache;
    };

    /**
     * Perform a Ajax request.
     * @param {String} method HTTP method (GET, POST).
     * @param {String} url URL of request.
     * @param {String|Object} data POST data of request, can by a string or javascript object. The javascript object will be converted in JSON string.
     * @param {String} success Callback if the request is executed with success.
     * @param {String} faild Callback if the request was failled.
     * @param {Object
    }
    options Options object.*@param {
        Object} options.headers List of HTTP headers.
     * @param {Object} options.requestFormat mime type of predefined value, json, xml or urlencoded.
     */
    bemap.ajax = function(method, url, data, success, failled, options) {
      var opt = options || {};
      var xhr = new XMLHttpRequest();
      var called = false;

      xhr.open(method, url, true);

      if(data instanceof Object) {
        data = JSON.stringify(data);
        if(!opt.requestFormat) {
          opt.requestFormat = "json";
        }
      }

      if(opt.requestFormat) {
        if(!opt.headers) {
          opt.headers = [];
        }

        if(opt.requestFormat == 'json') {
          opt.headers.push({"key": "Content-Type", "value": "application/json"});
        } else if(opt.requestFormat == 'xml') {
          opt.headers.push({"key": "Content-Type", "value": "text/xml"});
        } else if(opt.requestFormat == 'urlencoded') {
          opt.headers.push({"key": "Content-Type", "value": "application/x-www-form-urlencoded"});
        } else {
          opt.headers.push({"key": "Content-Type", "value": opt.requestFormat});
        }
      }

      if(opt.headers) {
        for(var i = 0; i < opt.headers.length; i++) {
          var header = opt.headers[i];
          xhr.setRequestHeader (header.key, header.value);
        }
      }

      xhr.onreadystatechange = function() {
        if (!called && (!this.readyState || xhr.readyState === 4 || this.readyState === 'complete' || this.readyState === 'loaded')) {
          called = true;
          var doc = xhr.response || xhr.responseText || xhr.responseXML;
          if (xhr.status == 200) {
            success(xhr, doc);
          } else {
            if (typeof(failled) === 'function') {
              failled(xhr, doc);
            }
            console.error("Status " + xhr.status, url);
          }
        }
      };

      xhr.send(data);
    };

    /**
     * Load a JavaScript file.
     * @param {String} src Script name with path.
     * @param {Object} options
     */
    bemap._require_cache = [];
    bemap.require = function(src, options) {
      var key, inCacheSrc, found = false;

      for (key in bemap._require_cache) {
        inCacheSrc = bemap._require_cache[key];
        if (inCacheSrc == src) {
          found = true;
        }
      }

      if (!found) {
        var head = document.head || document.getElementsByTagName('HEAD').item(0) || document.documentElement;
        var tag = document.createElement('script');

        if (!head || !tag) {
          console.error("Unsupport browser!");
        }

        tag.type = 'text/javascript';
        if (src.charAt(0) == '/') {
          tag.src = src;
        } else {
          tag.src = this.getCurrentPath() + src;
        }

        var opt = options || {};
        if (typeof(opt.success) === 'function') {
          var called = false;
          tag.onload = tag.onreadystatechange = function() {
            if (!called && (!this.readyState || xhr.readyState === 4 || this.readyState === 'complete' || this.readyState === 'loaded')) {
              called = true;
              if (xhr.Status == 200) {
                opt.success(xhr, doc);
              } else {
                if (typeof(opt.faild) === 'function') {
                  faild(xhr, doc);
                }
              }
            }
          };
        }

        tag.onerror = function() {
          console.error("Cannont load the library '" + src + "'");
        };

        head.appendChild(tag);
        bemap._require_cache.push(src);
      }
    };

    /**
     * @classdesc
     * Base class for Exception.
     *
     * @constructor
     * @param {String} message.
     * @param {bemap.Exception} cause.
     */
    bemap.Exception = function(message, cause) {
      this.message = message;
      this.cause = cause ? cause : null;
    };

    /**
     * Return the message of exception.
     * @return {String} Return the message of exception.
     */
    bemap.Exception.prototype.getMessage = function() {
      return this.message;
    };

    /**
     * Return the cause of exception.
     * @return {bemap.Exception} Return the cause of exception.
     */
    bemap.Exception.prototype.getCause = function() {
      return this.cause;
    };

    /**
     * Return stack of exceptions.
     * @return {String} Return stack of exceptions.
     */
    bemap.Exception.prototype.getStack = function() {
      var exception = this,
        stack = "";
      while (true) {
        stack = exception.message + "\n";
        if (exception.cause === null) {
          break;
        } else {
          exception = exception.cause;
        }
      }
      return stack;
    };

    /**
     * Print stack of exceptions.
     * @return {String} Print stack of exceptions.
     */
    bemap.Exception.prototype.printStack = function() {
      console.error(this.getStack());
    };

    /**
     * @classdesc
     * Base class for Context.
     *
     * @constructor
     * @param {object} options.
     */
    bemap.Context = function(options) {
      var opts = options || {};

      /**
       * Define the protocol used. The HTTP or HTTPS, by default the HTTP.
       * @protected
       * @type {string}
       */
      this.protocol = opts.secure ? 'https' : 'http';

      /**
       * Define the host name of BeMap server. By default "bemap-beta.benomad.com".
       * @protected
       * @type {string}
       */
      this.host = opts.host || 'bemap-beta.benomad.com';

      /**
       * Define the path of bgis context. The string must be start with / character. By default "/bgis/".
       * @protected
       * @type {string}
       */
      this.path = opts.path || '/bgis/';

      /**
       * Define the login.
       * @protected
       * @type {string}
       */
      this.login = opts.login;

      /**
       * Define the Password.
       * @protected
       * @type {string}
       */
      this.password = opts.password;

      /**
       * Heap cache of full URL to BeMap context.
       * @private
       * @type {string}
       */
      this.cacheBaseUrl = null;

      /**
       * Heap cache of base 64 authentication.
       * @private
       * @type {string}
       */
      this.cacheAuth = null;

      /**
       * Set the authentication parameters in POST data of request.
       * @private
       * @type {boolean}
       */
      this.authInPost = opts.authInPost ? true : false;

      /**
       * The default BeMap Geoserver
       * @private
       * @type {string}
       */
      this.geoserver = opts.geoserver ? opts.geoserver : undefined;
    };

    /**
     * Return the BaMap URL.
     * @return {String} BeMap URL
     */
    bemap.Context.prototype.getBaseUrl = function() {
      if (!this.cacheBaseUrl) {
        this.cacheBaseUrl = this.protocol + "://" + this.host + this.path;
      }
      return this.cacheBaseUrl;
    };

    /**
     * Return the BaMap Authentication.
     * @return {String} BeMap URL
     */
    bemap.Context.prototype.getAuthUrlParams = function() {
      if (this.login && this.password && !this.cacheAuth) {
        this.cacheAuth = "appid=" + this.login + "&appcode=" + this.password;
      }
      return this.cacheAuth;
    };

    /**
     * Set to true if the authentication parameters will be write in the POST data of request.
     */
    bemap.Context.prototype.setAuthInPost = function(authInPost) {
      this.authInPost = authInPost;
    };

    /**
     * Return true if the authentication parameters will be write in the POST data of request.
     * @return {boolean} true if the authentication parameters will be write in the POST data of request..
     */
    bemap.Context.prototype.isAuthInPost = function() {
      return this.authInPost;
    };

    /**
     * Return the default BaMap Geoserver of context.
     * @return {String} BeMap Geoserver
     */
    bemap.Context.prototype.getGeoserver = function() {
      return this.geoserver;
    };

    /**
     * Perform a HTTP Post request.
     * @param {Object} options
     */
    bemap.Context.prototype.post = function(options) {
      var opt = options || {};
      return this;
    };