Class.Mutators.Binds = function(self, methods) {
 
   $splat(methods).each(function(method){
      var fn = self[method];
      self[method] = function(){
         return fn.apply(self, arguments);
      };
   });
 
};

Element.counter = 1;

Element.implement({

  upwards: function(iterator) {
    var element = this;
    while (element) {
      if (iterator(element)) return element;
      element = element.getParent ? element.getParent() : null;
    }
    return element;
  },

  upwardsElement: function(classname) {
    return this.upwards(function(e) {
      if (e.hasClass)
        return e.hasClass(classname);
    });
    return null;
  },

  hasAttribute: function(attribute) {
    return this.getAttributeNode(attribute);
  },

  identify: function() {
    var id = this.getAttribute('id');
    if (id) return id;
    do { id = 'anonymous_element_' + Element.counter++ } while ($(id));
    this.setAttribute('id', id);
    return id;
  },

  focusFirstElement: function() {
    if (this.get('tag') != 'form') return;
    if (this.elements.length <= 0) return;
    // Find first non-hidden input
    for (var i = 0; i < this.elements.length; i++) {
      if (this.elements[i].type == 'hidden') continue;
      this.elements[i].focus();
      break;
    }
  }

});

Element.Events.keyescape = {
  base: 'keyup',
  condition: function(e) {
    return e.key == 'esc';
  }
};

String.implement({

  sprintf: function(params) {
    var _params = $A(params).copy();
    return this.replace(/%[a-z0-9]{1}/ig, function(value) {
      try {
        return (_params.length > 0) ? _params.shift() : '';
      } catch(e) {
        return '';
      }
    });
  }

});
