(function() {
  const collector = (function() {
    function CS(collection) {
      let i = 0,
        len = collection.length;
      for(; i < len; i++) {
        this[i] = collection[i];
      }
      this.concat = Array.prototype.concat;
      this.each = Array.prototype.forEach;
      this.filter = Array.prototype.filter;
      this.indexOf = Array.prototype.indexOf;
      this.length = len;
      this.map = Array.prototype.map;
      this.push = Array.prototype.push;
      this.some = Array.prototype.some;
      this.slice = Array.prototype.slice;
      this.splice = Array.prototype.splice;
    }
    function _isSimple(selector) {
      return (/ /g.test(selector) === false);
    }
    function _isSimpleID(selector) {
      return (
        (typeof selector === `string`) &&
        (_isSimple(selector)) &&
        (selector[0] === `#`)
      );
    }
    function _isSimpleClass(selector) {
      return (
        (typeof selector === `string`) &&
        (_isSimple(selector)) &&
        (selector[0] === `.`)
      );
    }
    function $(selector) {
      let collection, cleanedSelector;

      if(typeof selector === `string`) { cleanedSelector = selector.slice(1); }

      collection = (!selector ? [] :
            (typeof selector === `string`) ? (((_isSimpleID(selector)) ? [document.getElementById(cleanedSelector)] : (_isSimpleClass(selector)) ? document.getElementsByClassName(cleanedSelector) : document.querySelectorAll(selector) )) :
            (selector instanceof CS) ? selector :
            (typeof selector === `object` && (selector.nodeType === 1 || selector.nodeType === 9)) ? [selector] :
            (selector.constructor === Array) ? selector : [] );

      return new CS(collection);
    }
    $.extend = function (obj) {
      let _this = this, i;
      if (arguments.length > 2) {
        return Error(`$.extend expects at most 2 arguments. Old object and New object`);
      }
      if (arguments.length > 1) {
        _this = arguments[0];
        obj = arguments[1];
      }

      for(i in obj) {
        if(obj.hasOwnProperty(i)) {
          _this[i] = obj[i];
        }
      }

      return _this;
    };
    $.plugin = function (name, func) {
      CS.prototype[name] = func;
    };
    $.matches = function(collection, context) {
      if(collection.constructor !== Array && collection instanceof CS === false) {
        collection = [collection];
      }
      let EP = Element.prototype,
          matches = EP.matches || EP.webkitMatchesSelector || EP.mozMatchesSelector || EP.msMatchesSelector;

      return collection.filter((node) => {
        if (node !== null && (node.nodeType === 1 || node.nodeType === 9)) {
          return matches.call(node, context);
        }
      });
    };

    return $;
  })();

  if (window.$ === undefined) { window.$ = collector; }
  if (window.collector === undefined) { window.collector = collector; }
})();