/* GM */

var GM = {};

GM.namespace = function ()
{
  var i, j,
      root,
      parts;
  
  for (i = 0; i < arguments.length; i += 1) {
    root  = GM;
    parts = arguments[i].split('.');

    for (j = 1; j < parts.length; j += 1) {
      root[parts[j] ] = root[parts[j] ] || {};
      root = root[parts[j] ];
    }
  }
  
  return root;
};

/* GM.event */

GM.namespace('GM.event');

GM.event = function ()
{
  var handlers = [];

  return {
   
    register: function (element, event, func, context)
    {
      context  = context || element;
      
      var i,
          wrap = function (e) {
            func.call(context, e);
          };
    
      for (i = 0; i < handlers.length; i += 1) {
        if (handlers[i][0] === element && handlers[i][1] === event && handlers[i][2] === func) {
          alert([handlers[i], element, event, func, context]);
          return;
        }
      }
      handlers.push([element, event, func, wrap]);
    
      if (event === 'readystatechange') {
        element.onreadystatechange = wrap;
      } else if (element.attachEvent) {
        element.attachEvent('on' + event, wrap);
      } else if (element.addEventListener) {
        element.addEventListener(event, wrap, false);
      }
    },
    
    unregister: function (element, event, func)
    {
      for (var i = 0; i < handlers.length; i += 1) {
        if (handlers[i][0] === element && handlers[i][1] === event && handlers[i][2] === func) {
          if (event === 'readystatechange') {
            element.onreadystatechange = null;
          } else if (element.detachEvent) {
            element.detachEvent('on' + event, handlers[i][3]);
          } else if (element.removeEventListener) {
            element.removeEventListener(event, handlers[i][3], false);
          }
          
          handlers.splice(i, 1);
          return;
        }
      }
    },
    
    get: function (e)
    {
      return e || window.event;
    },
    
    getTarget: function (e)
    {
      e = GM.event.get(e);
      
      return e.target || e.srcElement;
    },
    
    cancelBubble: function (e)
    {
      e = GM.event.get(e);
            
      if (e.stopPropagation) {
        e.stopPropagation();
      } else {
        e.cancelBubble = true;
      }
      
      return false;
    },
    
    preventDefault: function (e)
    {
      e = GM.event.get(e);
            
      if (e.preventDefault) {
        e.preventDefault();
      } else {
        e.returnValue = false;
      }
      
      return false;
    },
    
    mouseClicked: function (event, whichNumber, buttonNumber)
    {
      event = GM.event.get(event);
      buttonNumber = buttonNumber || whichNumber;
      
      if (event.which && whichNumber && event.which === whichNumber) {
        return true;
      }
      if (event.button && buttonNumber && event.button === buttonNumber) {
        return true;
      }
      
      return false;
    },
    
    keyPressed: function (event, number)
    {
      event = GM.event.get(event);
      
      return (event.keyCode === number);
    },
    
    getPosition: function (e)
    {
      e = GM.event.get(e);
      var position = {x: 0, y: 0};
      
      if (e.pageX || e.pageY)   {
        position.x = e.pageX;
        position.y = e.pageY;
      } else if (e.clientX || e.clientY)  {
        position.x = e.clientX + document.body.scrollLeft +
          document.documentElement.scrollLeft;
        position.y = e.clientY + document.body.scrollTop +
          document.documentElement.scrollTop;
      }
      
      return position;
    }
  };
}();

/* GM.dom */

GM.namespace('GM.dom');

GM.dom.body = function ()
{
  return {

    getHeight: function ()
    {
      var scrollHeight = 0,
          bodyHeight = 0,
          clientHeight = 0;
      
      if (document.documentElement && document.documentElement.scrollHeight) {
        scrollHeight = document.documentElement.scrollHeight;
      }
      if (document.documentElement && document.documentElement.clientHeight) {
        clientHeight = document.documentElement.clientHeight;
      }
      if (document.body && document.body.scrollHeight) {
        bodyHeight = document.body.scrollHeight;
      }
      
      return Math.max(scrollHeight, bodyHeight, clientHeight);
    },
    
    getWidth: function ()
    {
      var scrollWidth = 0,
          bodyWidth = 0,
          clientWidth = 0;
      
      if (document.documentElement && document.documentElement.scrollWidth) {
        scrollWidth = document.documentElement.scrollWidth;
      }
      if (document.documentElement && document.documentElement.clientWidth) {
        clientWidth = document.documentElement.clientWidth;
      }      
      if (document.body && document.body.scrollWidth) {
        bodyWidth = document.body.scrollWidth;
      }
    
      return Math.max(scrollWidth, bodyWidth, clientWidth);
    }
  };
}();

GM.dom.form = function ()
{
  return {
    
    focus: function (form)
    {
      if (form.elements) {
        for (var i = 0; i < form.elements.length; i += 1) {
          if (form.elements[i].nodeName.toLowerCase() !== 'fieldset' && form.elements[i].type !== 'hidden') {
            form.elements[i].focus();
            return;
          }
        }
      }
    }
  };
}();

GM.dom.removeSelection = function (e)
{
  var target = GM.event.getTarget(e);
  
  if (window.getSelection) {
    window.getSelection().collapse(target, 0);
  } else if (document.selection) {
    document.selection.empty();
  }  
};

GM.dom.center = function (element)
{
  element.style.position   = 'absolute';
  element.style.left       = '50%';
  element.style.top        = '50%';
  element.style.marginLeft = '-' + (element.offsetWidth / 2) + 'px';
  element.style.marginTop  = '-' + (element.offsetHeight / 2) + 'px';
};

GM.dom.getOffset = function (object)
{
  var left = 0;
  var top  = 0;
    
  if (object.offsetParent) {
    while (object) {
      left += object.offsetLeft;
      top  += object.offsetTop;
      
      object = object.offsetParent;
    }
      
    return {'left': left, 'top': top};
  } 
};

GM.dom.getElementsByClassName = function (className, tagName, root)
{
  tagName = tagName || '*';
  root    = root || document;
  
  var i,
      results = [],
      elements = root.getElementsByTagName(tagName);
  
  for (i = 0; i < elements.length; i += 1) {
    if (elements[i].className.indexOf(className) !== -1) {
      results.push(elements[i]);
    }
  }
  
  return results;
};

GM.dom.getParentByClassName = function (className, root)
{
  if (root.parentNode) {
    if (root.parentNode.className && root.parentNode.className.indexOf(className) !== -1) {
      return root.parentNode;
    } else {
      return GM.dom.getParentByClassName(className, root.parentNode);
    }
  }
};

GM.dom.getFamilyByClassName = function (className, root, results)
{
  results = results || [];

  for (var i = 0; i < root.childNodes.length; i += 1) {
    if (root.childNodes[i].className && root.childNodes[i].className.indexOf(className) !== -1) {
      results.push(root.childNodes[i]);
    }
  }
  
  if (root.parentNode && root.parentNode.childNodes) {
    GM.dom.getFamilyByClassName(className, root.parentNode, results);
  }
  
  return results;
};

GM.dom.Lock = function (values)
{
  var hidden = [];

  values = values || {};
  values.color   = (typeof values.color   !== 'undefined') ? values.color   : '333';
  values.opacity = (typeof values.opacity !== 'undefined') ? values.opacity : 0.5;
  values.cursor  = (typeof values.cursor  !== 'undefined') ? values.cursor  : null;
  values.zIndex  = (typeof values.zIndex  !== 'undefined') ? values.zIndex  : 1;

  var lock = document.createElement('div');
  document.body.appendChild(lock);
  
  lock.style.position        = 'absolute';
  lock.style.left            = 0;
  lock.style.top             = 0;
  lock.style.width           = GM.dom.body.getWidth() + 'px';
  lock.style.height          = GM.dom.body.getHeight() + 'px';
  lock.style.backgroundColor = '#' + values.color;
  lock.style.cursor          = values.cursor;
  lock.style.opacity         = values.opacity;
  lock.style.filter          = 'alpha(opacity=' + (values.opacity * 100) + ')';
  lock.style.zIndex          = values.zIndex;
    
  if (values.opacity > 0) {
    var selects = document.getElementsByTagName('select');
          
    for (i = 0; i < selects.length; i += 1) {
      if (selects[i].style.visibility != 'hidden') {
        selects[i].style.visibility = 'hidden';
        hidden.push(selects[i]);
      }
    }
  }
  
  return {
  
    getElement: function ()
    {
      return lock;
    },
  
    unlock: function ()
    {
      lock.style.cursor = null;
      lock.parentNode.removeChild(lock);
      
      for (var i = 0; i < hidden.length; i += 1) {
        hidden[i].style.visibility = 'visible';
      }
    }  
  };
};

GM.dom.Boundaries = function (left, right, top, bottom)
{
  this.set(left, right, top, bottom);
};

GM.dom.Boundaries.prototype =
{
  checkX: function (object)
  {
    if (object.right <= this.right && object.left >= this.left) {
      return true;
    }
    return false;
  },
  
  checkY: function (object)
  {    
    if (object.bottom <= this.bottom && object.top >= this.top) {
      return true;
    }
    return false;                    
  },
  
  set: function (left, right, top, bottom)
  {
    this.left   = left;
    this.right  = right;
    this.top    = top;
    this.bottom = bottom;
  }
};

GM.dom.Drag = function (object, handler, parent, zIndex)
{
  this.init(object, handler, parent, zIndex);
};

GM.dom.Drag.prototype =
{
  object: null,
  
  handler: null,
  
  parent: null,
  
  zIndex: 1,

  beginPosition: null,
  
  stylePosition: null,
  
  windowBoundaries: new GM.dom.Boundaries(0, GM.dom.body.getWidth(), 0, GM.dom.body.getHeight() ),
  
  objectBoundaries: new GM.dom.Boundaries(0, 0, 0, 0),

  init: function (object, handler, parent, zIndex)
  {
    this.object  = object;
    this.handler = handler;
    this.parent  = parent;
    this.zIndex  = zIndex || this.zIndex;
    
    if (handler) {
      GM.event.register(handler, 'mousedown', this.startDrag, this);
      handler.style.cursor = 'move';
    } else {
      GM.event.register(object, 'mousedown', this.startDrag, this);
    }    
  },
  
  removeHandlers: function ()
  {
    var element = (this.handler) ? this.handler : this.object;
    GM.event.unregister(element, 'mousedown', this.startDrag);
  },

  startDrag: function (e)
  {    
    if (GM.event.mouseClicked(e, 1) ) {
      var object = this.object;
      
      this.beginPosition = GM.event.getPosition(e);
      this.stylePosition = object.style.position;
            
      object.oldZIndex = object.style.zIndex;
            
      object.style.zIndex   = this.zIndex;
      object.style.cursor   = 'move';
      object.style.position = (!object.style.position) ? 'relative' : object.style.position;
  
      object.style.top  = (object.style.position === 'relative') ? 0 : object.offsetTop - parseInt(object.style.marginTop, 10) + 'px';
      object.style.left = (object.style.position === 'relative') ? 0 : object.offsetLeft - parseInt(object.style.marginLeft, 10) + 'px';
  
      object.direction = {};
  
      GM.event.register(document, 'mousemove', this.drag, this);
      GM.event.register(document, 'mouseup', this.stopDrag, this);
      
      return GM.event.preventDefault(e);
    }    
  },
  
  drag: function (e)
  {
    var position         = GM.event.getPosition(e),
        difX             = position.x - this.beginPosition.x,
        difY             = position.y - this.beginPosition.y,
        newLeft          = this.object.offsetLeft + difX,
        newRight         = newLeft + this.object.offsetWidth,
        newTop           = this.object.offsetTop + difY,
        newBottom        = newTop  + this.object.offsetHeight,
        parentBoundaries = (this.parent && this.parent.boundaries) ? this.parent.boundaries : this.windowBoundaries;
      
    this.beginPosition = position;
    this.objectBoundaries.set(newLeft, newRight, newTop, newBottom);
      
    if (parentBoundaries.checkX(this.objectBoundaries)) {
      this.object.style.left = (parseInt(this.object.style.left, 10) + difX) + 'px';
    }
    if (parentBoundaries.checkY(this.objectBoundaries)) {
      this.object.style.top = (parseInt(this.object.style.top, 10) + difY) + 'px';
    }
    
    this.object.direction.x = (difX < 0) ? 'left' : 'right';
    this.object.direction.y = (difY < 0) ? 'up' : 'down';
                
    return GM.event.preventDefault(e);
  },
  
  stopDrag: function (e)
  {
    this.object.style.zIndex   = this.object.oldZIndex;
    this.object.style.cursor   = '';
    this.object.style.position = this.stylePosition;
    
    this.beginPosition = null;
    this.stylePosition = null;
    
    this.object.direction = null;
    
    GM.event.unregister(document, 'mousemove', this.drag);
    GM.event.unregister(document, 'mouseup', this.stopDrag);
    
    return GM.event.preventDefault(e);
  }
};

GM.dom.Sort = function (list, callback)
{
  this.init(list, callback);
};

GM.dom.Sort.prototype =
{
  list: null,
  
  callbackFunction: null,
  
  selected: null,
  
  items: null,

  drags: [],

  threshold: 7,
  
  init: function (list, callback)
  {
    this.list = list;
    this.callbackFunction = callback;
    
    this.addHandlers();
  },

  reInit: function ()
  {
    if (this.list && this.callbackFunction) {
      this.removeHandlers();
      this.addHandlers();
    }
  },

  addHandlers: function ()
  {
    this.items = GM.dom.getElementsByClassName('drag', 'div', this.list);
    for (var i = 0; i < this.items.length; i += 1) {
      this.drags[i] = new GM.dom.Drag(this.items[i], '', this.list);
      GM.event.register(this.items[i], 'mousedown', this.startSort, this);        
    }
  },

  removeHandlers: function ()
  {
    for (var i = 0; i < this.items.length; i += 1) {
      this.drags[i].removeHandlers();
      GM.event.unregister(this.items[i], 'mousedown', this.startSort);        
    }
  },

  startSort: function (e)
  {
    if (GM.event.mouseClicked(e, 1) ) {
      this.selected = GM.dom.getParentByClassName('drag', GM.event.getTarget(e) );
      
      this.list.boundaries     = new GM.dom.Boundaries(0, this.list.offsetWidth, 0, this.list.offsetHeight);
      this.list.style.position = 'relative';

      GM.event.register(document, 'mousemove', this.sort, this);
      GM.event.register(document, 'mouseup', this.stopSort, this);
    }
  },
  
  sort: function ()
  {
    var i, j,
        positionItem,
        positionSelected,
        sBoundaries,
        iBoundaries;
  
    for (i = 0; i < this.items.length; i += 1) {
      if (this.items[i] !== this.selected) {
        for (j = 0; j < this.selected.parentNode.childNodes.length; j += 1) {
          if (this.selected.parentNode.childNodes[j] === this.selected) {
            positionSelected = j;
          } else if (this.selected.parentNode.childNodes[j] === this.items[i]) {
            positionItem = j;
          }
        }

        if (this.selected.direction.y === 'up' && positionItem < positionSelected) {
          sBoundaries = new GM.dom.Boundaries(0, 0, this.selected.offsetTop, this.selected.offsetTop);
          iBoundaries = new GM.dom.Boundaries(0, 0, this.items[i].offsetTop, this.items[i].offsetTop + this.threshold);  
          if (iBoundaries.checkY(sBoundaries)) {
            this.selected.style.top = this.threshold + 'px';
            this.list.insertBefore(this.selected, this.items[i]);
            this.list.boundaries = new GM.dom.Boundaries(0, this.list.offsetWidth, 0, this.list.offsetHeight);
            return;
          }
        } else if (this.selected.direction.y === 'down' && positionItem > positionSelected) {
          sBoundaries = new GM.dom.Boundaries(0, 0, this.selected.offsetTop + this.selected.offsetHeight,
                                             this.selected.offsetTop + this.selected.offsetHeight);
          iBoundaries = new GM.dom.Boundaries(0, 0, this.items[i].offsetTop + this.items[i].offsetHeight - this.threshold,
                                             this.items[i].offsetTop + this.items[i].offsetHeight);          
          if (iBoundaries.checkY(sBoundaries)) {
            this.selected.style.top = (-1) * this.threshold + 'px';
            if (this.items[i].nextSibling) {
              this.list.insertBefore(this.selected, this.items[i].nextSibling);
            } else {
              this.list.appendChild(this.selected);
            }
            this.list.boundaries = new GM.dom.Boundaries(0, this.list.offsetWidth, 0, this.list.offsetHeight);
            return;
          }
        }
      }
    }      
  },
  
  stopSort: function ()
  {
    var selected = this.selected,
        items    = GM.dom.getElementsByClassName('drag', 'div', this.list);
      
    this.selected.style.top  = 0;
    this.selected.style.left = 0;
    this.list.style.position = '';  
    
    this.selected = null;
      
    GM.event.unregister(document, 'mousemove', this.sort);
    GM.event.unregister(document, 'mouseup', this.stopSort);
    
    if (this.callbackFunction) {
      this.callbackFunction(items, selected);
    }
  }  
};

/* GM.Request */

GM.request = function ()
{
  var parameters, queue = [], request, submitValue, iframe;

  GM.event.register(document, 'click', captureSubmit);
  
  function captureSubmit(e)
  {
    var target = GM.event.getTarget(e);
    
    if (target.nodeName.toLowerCase() === 'input' && target.type && target.type.toLowerCase() === 'submit') {
      submitValue = '&' + encodeURIComponent(target.name) + '=' + encodeURIComponent(target.value);
    }
  }

  function setRequest()
  {
    if (window.XMLHttpRequest) {
      request = new XMLHttpRequest();
    } else if (window.ActiveXObject) {
      request = new ActiveXObject("Microsoft.XMLHTTP");
    }
    return request;
  }
  
  function isUpload(form)
  {
    for (var i = 0; i < form.elements.length; i += 1) {
      if (form.elements[i].type && form.elements[i].type === 'file') {
        return true;
      }
    }
    return false;
  }
  
  function getFormData(form)
  {
    var i, j,
        element,
        hasSubmit = false,
        value,
        result = '';
        
    for (i = 0; i < form.elements.length; i += 1) {
      element = form.elements[i];
      
      if (!element.disabled) {
        switch(element.type) {
        case 'checkbox':
        case 'radio':
          if (element.checked) {
            result += '&' + encodeURIComponent(element.name) + '=' + encodeURIComponent(element.value);
          }
          break;
        case 'hidden':
        case 'text':
        case 'textarea':
          result += '&' + encodeURIComponent(element.name) + '=' + encodeURIComponent(element.value);
          break;
        case 'select-one':
        case 'select-multiple':
          for (j = 0; j < element.options.length; j += 1) {
            if (element.options[j].selected) {
              value   = (element.options[j].value) ? element.options[j].value : element.options[j].text;
              result += '&' + encodeURIComponent(element.name) + '=' + encodeURIComponent(value);
            }
          }
          break;
        case 'submit':
          if (!hasSubmit) {
            if (submitValue) {
              result += submitValue;
              submitValue = null;
            } else {
              result += '&' + encodeURIComponent(element.name) + '=' + encodeURIComponent(element.value);
            }
            
            hasSubmit = true;
          }
        default:
          break;
        }
      }
    }
    
    return result;
  }
  
  function addFormData(form, data)
  {
    data += '&iframe=true';
  
    var i,
        nodes = [],
        arguments = data.split('&');
        
    for (i = 0; i < arguments.length; i += 1) {
      if (arguments[i].indexOf('=') > 0) {
        nodes[i] = document.createElement('input');
        nodes[i].type = 'hidden';
        nodes[i].name  = arguments[i].substring(0, arguments[i].indexOf('=') );
        nodes[i].value = arguments[i].substring(arguments[i].indexOf('=') + 1);
        form.appendChild(nodes[i]);
      }
    }
    
    return nodes;        
  }
  
  return {
    
    send: function (params)
    {
      if (params.form && isUpload(params.form) ) {
        if (iframe) {
          queue.push(params);
          return;
        }  
        
        parameters = params;
          
        var i,
            dataElements = addFormData(parameters.form, parameters.data),
            iframeId = new Date().getTime();
      
        if (window.ActiveXObject) {
          iframe = document.createElement('<iframe name="iframe_' + iframeId + '" id="iframe_' + iframeId + '"/>');
        } else {
          iframe      = document.createElement('iframe');
          iframe.id   = 'iframe_' + iframeId;
          iframe.name = 'iframe_' + iframeId;
        }
        
        iframe.style.position  = 'absolute';
        iframe.style.visibility = 'hidden';
        iframe.style.left = '-1000px';
        iframe.style.top  = '-1000px';
        
        document.body.appendChild(iframe);
        
        GM.event.register(iframe, 'load', this.handleUpload, this);
        
        var oldTarget = parameters.form.target;
        
        parameters.form.target = iframe.id;
        parameters.form.submit();
        
        for (i = 0; i < dataElements.length; i += 1) {
          parameters.form.removeChild(dataElements[i]);
        }
        
        parameters.form.target = oldTarget;
      } else {
        if (request && request.readyState !== 4) {
          queue.push(params);
          return;
        } 
      
        parameters = params;
      
        parameters.data = parameters.data || '';
      
        if (parameters.form) {
          parameters.method = parameters.form.method;
          parameters.url    = parameters.form.action;
          parameters.data  += getFormData(parameters.form);
        }
        
        if (parameters.method === 'get' && parameters.data) {
          parameters.url += ( (parameters.url.indexOf('?') === -1) ? '?' : '&') + parameters.data;
          parameters.data = '';
        }
        
        if (parameters.async === undefined || parameters.async === null) {
          parameters.async = true;
        }
        
        request = request || setRequest();
        request.open(parameters.method, parameters.url, parameters.async);
        if (parameters.method === 'post') {
          request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
        }
        if (parameters.async || window.ActiveXObject) { // until https://bugzilla.mozilla.org/show_bug.cgi?id=313646 is fixed
          GM.event.register(request, 'readystatechange', this.handle, this);
        } else {
          GM.event.register(request, 'load', this.handle, this);
        }
        request.send(parameters.data);
      }
    },
    
    handle: function (e)
    {
      if (request.readyState === 4) {
        GM.event.unregister(request, 'readystatechange', this.handle);
        GM.event.unregister(request, 'load', this.handle);
        
        if (request.status === 200) {
          if (parameters.callback) {
            var context    = (parameters.context) ? parameters.context : window,
                object     = (parameters.object) ? parameters.object : {};
            object.request = request; 
            parameters.callback.call(context, e, object);
          }       
          this.finish();
        } else {
          alert(request.statusText + ' (' + request.status + '): ' + request.responseText);
          this.finish();
        }
      }
    },
    
    handleUpload: function (e)
    {
      GM.event.unregister(iframe, 'load', this.handleUpload);

      if (parameters.callback) {
        var context    = (parameters.context) ? parameters.context : window,
            object     = (parameters.object) ? parameters.object : {};
        object.request = {responseText: iframe.contentWindow.document.body.innerHTML}; 
        parameters.callback.call(context, e, object);
      }
     
      setTimeout(
        function () {
          iframe.parentNode.removeChild(iframe);
          iframe = null;
        }, 100
      );
     
      this.finish();
    },
    
    finish: function ()
    {
      if (queue[0]) {
        var params = queue[0];
        queue.splice(0, 1);
        this.send(params);          
      }
    }
  };
}();

/* Generic functions */

function formatNumber(number, decimals)
{
  var newNumber = number;
  
  if (!isNaN(number) ) {
    decimals = decimals || 0;
    
    var divider   = Math.pow(10, decimals);
    var newNumber = Math.round(number * divider) / divider;
    
    var separatorPosition = newNumber.toString().indexOf('.');
    var difference        = 0;
    
    if (separatorPosition === -1) {
      newNumber  = newNumber + '.';
      difference = decimals;
    } else {
      difference = decimals - (newNumber.toString().length - (separatorPosition + 1) );
    }
    
    for (var i = 0; i < difference; i += 1) {
      newNumber = newNumber + '0';
    }    
  }
  
  return newNumber;
}

/* Generic prototype functions */

if (typeof Array.prototype.indexOf !== 'function') {
  Array.prototype.indexOf = function (o) {
    for (var i = 0; i < this.length; i += 1) {
      if (this[i] === o) {
        return i;
      }
    }
    return -1;  
  };
}

if (typeof Function.prototype.inherit !== 'function') {
  Function.prototype.inherit = function (parent) {
    for (var m in parent.prototype) {
      this.prototype[m] = parent.prototype[m];
    }     
  };
}

if (typeof String.prototype.trim !== 'function') {
  String.prototype.trim = function() {
    return this.replace(/^\s+|\s+$/g,"");
  };
}

if (typeof String.prototype.ltrim !== 'function') {
  String.prototype.ltrim = function() {
    return this.replace(/^\s+/,"");
  };
}

if (typeof String.prototype.rtrim !== 'function') {
  String.prototype.rtrim = function() {
    return this.replace(/\s+$/,"");
  };
}
