<commit_before>"use strict";
(function(window) {
    var config = {
      silent: false
    }
    var directives = {};
    var components = {};

    /**
    * Converts attributes into key-value pairs
    * @param {Node} node
    * @return {Object} Key-Value pairs of Attributes
    */
    var extractAttrs = function(node) {
      var attrs = {};
      if(!node.attributes) return attrs;
      var rawAttrs = node.attributes;
      for(var i = 0; i < rawAttrs.length; i++) {
        attrs[rawAttrs[i].name] = rawAttrs[i].value
      }

      return attrs;
    }

    /**
    * Compiles a template with given data
    * @param {String} template
    * @param {Object} data
    * @return {String} Template with data rendered
    */
    var compileTemplate = function(template, data) {
      var code = template,
          re = /{{([A-Za-z0-9_.()\[\]]+)}}/gi;
      code.replace(re, function(match, p) {
        code = code.replace(match, "` + data." + p + " + `");
      });
      var compile = new Function("data", "var out = `" + code + "`; return out");
      var output = compile(data);
      return output;
    }

    /**
    * Gets Root Element
    * @param {String} html
    * @return {Node} Root Element
    */
    var getRootElement = function(html) {
      var dummy = document.createElement('div');
      dummy.innerHTML = html;
      return dummy.firstChild;
    }

    /**
    * Merges two Objects
    * @param {Object} obj
    * @param {Object} obj2
    * @return {Object} Merged Objects
    */
    function merge(obj, obj2) {
      for (var key in obj2) {
        if (obj2.hasOwnProperty(key)) obj[key] = obj2[key];
      }
      return obj;
    }

    function Moon(opts) {
        var _el = opts.el;
        var _data = opts.data;
        var _hooks = opts.hooks || {created: function() {}, mounted: function() {}, updated: function() {}, destroyed: function() {}};
        var _destroyed = false;
        var self = this;
        this.$el = document.querySelector(_el);
        this.$methods = opts.methods;
        this.$components = merge(opts.components || {}, components);
        this.$dom = {type: this.$el.nodeName, children: [], node: this.$el};

        // Change state when $data is changed
        Object.defineProperty(this, '$data', {
            get: function() {
                return _data;
            },
            set: function(value) {
                _data = value;
                this.build(this.$dom.children);
            },
            configurable: true
        });

        /**
        * Logs a Message
        * @param {String} msg
        */
        this.log = function(msg) {
          if(!config.silent) console.log(msg);
        }

        /**
        * Throws an Error
        * @param {String} msg
        */
        this.error = function(msg) {
          console.log("Moon ERR: " + msg);
        }

        /**
        * Creates an object to be used in a Virtual DOM
        * @param {String} type
        * @param {Array} children
        * @param {String} val
        * @param {Object} props
        * @param {Node} node
        * @return {Object} Object usable in Virtual DOM
        */
        this.createElement = function(type, children, val, props, node) {
          return {type: type, children: children, val: val, props: props, node: node};
        }

        /**
        * Create Elements Recursively For all Children
        * @param {Array} children
        * @return {Array} Array of elements usable in Virtual DOM
        */
        this.recursiveChildren = function(children) {
          var recursiveChildrenArr = [];
          for(var i = 0; i < children.length; i++) {
            var child = children[i];
            recursiveChildrenArr.push(this.createElement(child.nodeName, this.recursiveChildren(child.childNodes), child.textContent, extractAttrs(child), child));
          }
          return recursiveChildrenArr;
        }

        /**
        * Creates Virtual DOM
        * @param {Node} node
        */
        this.createVirtualDOM = function(node) {
          var vdom = this.createElement(node.nodeName, this.recursiveChildren(node.childNodes), node.textContent, extractAttrs(node), node);
          this.$dom = vdom;
        }

        /**
        * Compiles all Components to HTML
        */
        this.compileComponents = function() {
          for(var componentName in this.$components) {
            var component = this.$components[componentName];
            var foundComponents = Array.prototype.slice.call(this.$el.getElementsByTagName(componentName));
            for(var i = 0; i < foundComponents.length; i++) {
              var foundComponent = foundComponents[i];
              var props = extractAttrs(foundComponent);
              foundComponent.outerHTML = compileTemplate(component.template, props);
            }
          }
        }

        /**
        * Sets Value in Data
        * @param {String} key
        * @param {String} val
        */
        this.set = function(key, val) {
          this.$data[key] = val;
          if(!_destroyed) this.build(this.$dom.children);
          if(_hooks.updated) {
            _hooks.updated();
          }
        }

        /**
        * Gets Value in Data
        * @param {String} key
        * @return {String} Value of key in data
        */
        this.get = function(key) {
          return this.$data[key];
        }

        /**
        * Calls a method
        * @param {String} method
        */
        this.method = function(method) {
          this.$methods[method]();
        }

        this.destroy = function() {
          Object.defineProperty(this, '$data', {
            set: function(value) {
              _data = value;
            }
          });
          _destroyed = true;
          if(_hooks.destroyed) _hooks.destroyed();
        }

        // Default Directives
        directives["m-if"] = function(el, val, vdom) {
          var evaluated = new Function("return " + val);
          if(!evaluated()) {
            el.textContent = "";
          } else {
            el.textContent = compileTemplate(vdom.val, self.$data);
          }
        }

        directives["m-show"] = function(el, val, vdom) {
          var evaluated = new Function("return " + val);
          if(!evaluated()) {
            el.style.display = 'none';
          } else {
            el.style.display = 'block';
          }
        }

        directives["m-on"] = function(el, val, vdom) {
          var splitVal = val.split(":");
          var eventToCall = splitVal[0];
          var methodToCall = splitVal[1];
          el.addEventListener(eventToCall, function() {
            self.method(methodToCall);
          });
          el.removeAttribute("m-on");
          delete vdom.props["m-on"];
        }

        directives["m-model"] = function(el, val, vdom) {
          el.value = self.get(val);
          el.addEventListener("input", function() {
            self.set(val, el.value);
          });
          el.removeAttribute("m-model");
          delete vdom.props["m-model"];
        }

        directives["m-once"] = function(el, val, vdom) {
          vdom.val = el.textContent;
          for(var child in vdom.children) {
            vdom.children[child].val = compileTemplate(vdom.children[child].val, self.$data);
          }
        }

        directives["m-text"] = function(el, val, vdom) {
          el.textContent = val;
        }

        directives["m-html"] = function(el, val, vdom) {
          el.innerHTML = val;
        }

        directives["m-mask"] = function(el, val, vdom) {

        }

        // directives["m-for"] = function(el, val, vdom) {
        //   var splitVal = val.split(" in ");
        //   var alias = splitVal[0];
        //   var arr = self.get(splitVal[1]);
        //   var clone = el.cloneNode(true);
        //   var oldVal = vdom.val;
        //   var compilable = vdom.val.replace(new RegExp(alias, "gi"), splitVal[1] + '[0]');
        //   el.innerHTML = compileTemplate(compilable, self.$data);
        //   for(var i = 1; i < arr.length; i++) {
        //     var newClone = clone.cloneNode(true);
        //     var compilable = oldVal.replace(new RegExp(alias, "gi"), splitVal[1] + '[' + i + ']');
        //     newClone.innerHTML = compileTemplate(compilable, self.$data);
        //     var parent = el.parentNode;
        //     parent.appendChild(newClone);
        //   }
        //   vdom.val = el.textContent;
        //   delete vdom.props["m-for"];
        // }

        /**
        * Builds the DOM With Data
        * @param {Array} children
        */
        this.build = function(children) {
          for(var i = 0; i < children.length; i++) {
            var el = children[i];

            if(el.type === "#text") {
              el.node.textContent = compileTemplate(el.val, this.$data);
            } else if(el.props) {
              for(var prop in el.props) {
                var propVal = el.props[prop];
                var compiledProperty = compileTemplate(propVal, this.$data);
                var directive = directives[prop];
                if(directive) {
                  el.node.removeAttribute(prop);
                  directive(el.node, compiledProperty, el);
                }

                if(!directive) el.node.setAttribute(prop, compiledProperty);
              }
            }

            this.build(el.children);
          }
        }

        /**
        * Initializes Moon
        */
        this.init = function() {
          this.log("======= Moon =======");
          if(_hooks.created) {
            _hooks.created();
          }
          this.compileComponents();
          this.createVirtualDOM(this.$el);
          this.build(this.$dom.children);
          if(_hooks.mounted) {
            _hooks.mounted();
          }
        }

        // Initialize 🎉
        this.init();
    }

    /**
    * Sets the Configuration of Moon
    * @param {Object} opts
    */
    Moon.config = function(opts) {
      if(opts.silent) {
        config.silent = opts.silent;
      }
    }

    /**
    * Runs an external Plugin
    * @param {Object} plugin
    */
    Moon.use = function(plugin) {
      plugin.init(Moon);
    }

    /**
    * Creates a Directive
    * @param {String} name
    * @param {Function} action
    */
    Moon.directive = function(name, action) {
      directives["m-" + name] = action;
    }

    /**
    * Creates a Component
    * @param {String} name
    * @param {Function} action
    */
    Moon.component = function(name, action) {
      components[name] = action;
    }

    /**
    * Makes an AJAX Request
    * @param {String} method
    * @param {String} url
    * @param {Object} params
    * @param {Function} cb
    */
    Moon.ajax = function(method, url, params, cb) {
      var xmlHttp = new XMLHttpRequest();
      method = method.toUpperCase();
      if(typeof params === "function") {
        cb = params;
      }
      var urlParams = "?";
      if(method === "POST") {
        http.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
        for(var param in params) {
          urlParams += param + "=" + params[param] + "&";
        }
      }
      xmlHttp.onreadystatechange = function() {
      if (xmlHttp.readyState == 4 && xmlHttp.status == 200)
        cb(JSON.parse(xmlHttp.responseText));
      }
      xmlHttp.open(method, url, true);
      xmlHttp.send(method === "POST" ? urlParams : null);
    }

    window.Moon = Moon;
})(window);
<commit_msg>change props object instead<commit_after>"use strict";
(function(window) {
    var config = {
      silent: false
    }
    var directives = {};
    var components = {};

    /**
    * Converts attributes into key-value pairs
    * @param {Node} node
    * @return {Object} Key-Value pairs of Attributes
    */
    var extractAttrs = function(node) {
      var attrs = {};
      if(!node.attributes) return attrs;
      var rawAttrs = node.attributes;
      for(var i = 0; i < rawAttrs.length; i++) {
        attrs[rawAttrs[i].name] = rawAttrs[i].value
      }

      return attrs;
    }

    /**
    * Compiles a template with given data
    * @param {String} template
    * @param {Object} data
    * @return {String} Template with data rendered
    */
    var compileTemplate = function(template, data) {
      var code = template,
          re = /{{([A-Za-z0-9_.()\[\]]+)}}/gi;
      code.replace(re, function(match, p) {
        code = code.replace(match, "` + data." + p + " + `");
      });
      var compile = new Function("data", "var out = `" + code + "`; return out");
      var output = compile(data);
      return output;
    }

    /**
    * Gets Root Element
    * @param {String} html
    * @return {Node} Root Element
    */
    var getRootElement = function(html) {
      var dummy = document.createElement('div');
      dummy.innerHTML = html;
      return dummy.firstChild;
    }

    /**
    * Merges two Objects
    * @param {Object} obj
    * @param {Object} obj2
    * @return {Object} Merged Objects
    */
    function merge(obj, obj2) {
      for (var key in obj2) {
        if (obj2.hasOwnProperty(key)) obj[key] = obj2[key];
      }
      return obj;
    }

    function Moon(opts) {
        var _el = opts.el;
        var _data = opts.data;
        var _hooks = opts.hooks || {created: function() {}, mounted: function() {}, updated: function() {}, destroyed: function() {}};
        var _destroyed = false;
        var self = this;
        this.$el = document.querySelector(_el);
        this.$methods = opts.methods;
        this.$components = merge(opts.components || {}, components);
        this.$dom = {type: this.$el.nodeName, children: [], node: this.$el};

        // Change state when $data is changed
        Object.defineProperty(this, '$data', {
            get: function() {
                return _data;
            },
            set: function(value) {
                _data = value;
                this.build(this.$dom.children);
            },
            configurable: true
        });

        /**
        * Logs a Message
        * @param {String} msg
        */
        this.log = function(msg) {
          if(!config.silent) console.log(msg);
        }

        /**
        * Throws an Error
        * @param {String} msg
        */
        this.error = function(msg) {
          console.log("Moon ERR: " + msg);
        }

        /**
        * Creates an object to be used in a Virtual DOM
        * @param {String} type
        * @param {Array} children
        * @param {String} val
        * @param {Object} props
        * @param {Node} node
        * @return {Object} Object usable in Virtual DOM
        */
        this.createElement = function(type, children, val, props, node) {
          return {type: type, children: children, val: val, props: props, node: node};
        }

        /**
        * Create Elements Recursively For all Children
        * @param {Array} children
        * @return {Array} Array of elements usable in Virtual DOM
        */
        this.recursiveChildren = function(children) {
          var recursiveChildrenArr = [];
          for(var i = 0; i < children.length; i++) {
            var child = children[i];
            recursiveChildrenArr.push(this.createElement(child.nodeName, this.recursiveChildren(child.childNodes), child.textContent, extractAttrs(child), child));
          }
          return recursiveChildrenArr;
        }

        /**
        * Creates Virtual DOM
        * @param {Node} node
        */
        this.createVirtualDOM = function(node) {
          var vdom = this.createElement(node.nodeName, this.recursiveChildren(node.childNodes), node.textContent, extractAttrs(node), node);
          this.$dom = vdom;
        }

        /**
        * Compiles all Components to HTML
        */
        this.compileComponents = function() {
          for(var componentName in this.$components) {
            var component = this.$components[componentName];
            var foundComponents = Array.prototype.slice.call(this.$el.getElementsByTagName(componentName));
            for(var i = 0; i < foundComponents.length; i++) {
              var foundComponent = foundComponents[i];
              var props = extractAttrs(foundComponent);
              foundComponent.outerHTML = compileTemplate(component.template, {props:props});
            }
          }
        }

        /**
        * Sets Value in Data
        * @param {String} key
        * @param {String} val
        */
        this.set = function(key, val) {
          this.$data[key] = val;
          if(!_destroyed) this.build(this.$dom.children);
          if(_hooks.updated) {
            _hooks.updated();
          }
        }

        /**
        * Gets Value in Data
        * @param {String} key
        * @return {String} Value of key in data
        */
        this.get = function(key) {
          return this.$data[key];
        }

        /**
        * Calls a method
        * @param {String} method
        */
        this.method = function(method) {
          this.$methods[method]();
        }

        this.destroy = function() {
          Object.defineProperty(this, '$data', {
            set: function(value) {
              _data = value;
            }
          });
          _destroyed = true;
          if(_hooks.destroyed) _hooks.destroyed();
        }

        // Default Directives
        directives["m-if"] = function(el, val, vdom) {
          var evaluated = new Function("return " + val);
          if(!evaluated()) {
            el.textContent = "";
          } else {
            el.textContent = compileTemplate(vdom.val, self.$data);
          }
        }

        directives["m-show"] = function(el, val, vdom) {
          var evaluated = new Function("return " + val);
          if(!evaluated()) {
            el.style.display = 'none';
          } else {
            el.style.display = 'block';
          }
        }

        directives["m-on"] = function(el, val, vdom) {
          var splitVal = val.split(":");
          var eventToCall = splitVal[0];
          var methodToCall = splitVal[1];
          el.addEventListener(eventToCall, function() {
            self.method(methodToCall);
          });
          el.removeAttribute("m-on");
          delete vdom.props["m-on"];
        }

        directives["m-model"] = function(el, val, vdom) {
          el.value = self.get(val);
          el.addEventListener("input", function() {
            self.set(val, el.value);
          });
          el.removeAttribute("m-model");
          delete vdom.props["m-model"];
        }

        directives["m-once"] = function(el, val, vdom) {
          vdom.val = el.textContent;
          for(var child in vdom.children) {
            vdom.children[child].val = compileTemplate(vdom.children[child].val, self.$data);
          }
        }

        directives["m-text"] = function(el, val, vdom) {
          el.textContent = val;
        }

        directives["m-html"] = function(el, val, vdom) {
          el.innerHTML = val;
        }

        directives["m-mask"] = function(el, val, vdom) {

        }

        // directives["m-for"] = function(el, val, vdom) {
        //   var splitVal = val.split(" in ");
        //   var alias = splitVal[0];
        //   var arr = self.get(splitVal[1]);
        //   var clone = el.cloneNode(true);
        //   var oldVal = vdom.val;
        //   var compilable = vdom.val.replace(new RegExp(alias, "gi"), splitVal[1] + '[0]');
        //   el.innerHTML = compileTemplate(compilable, self.$data);
        //   for(var i = 1; i < arr.length; i++) {
        //     var newClone = clone.cloneNode(true);
        //     var compilable = oldVal.replace(new RegExp(alias, "gi"), splitVal[1] + '[' + i + ']');
        //     newClone.innerHTML = compileTemplate(compilable, self.$data);
        //     var parent = el.parentNode;
        //     parent.appendChild(newClone);
        //   }
        //   vdom.val = el.textContent;
        //   delete vdom.props["m-for"];
        // }

        /**
        * Builds the DOM With Data
        * @param {Array} children
        */
        this.build = function(children) {
          for(var i = 0; i < children.length; i++) {
            var el = children[i];

            if(el.type === "#text") {
              el.node.textContent = compileTemplate(el.val, this.$data);
            } else if(el.props) {
              for(var prop in el.props) {
                var propVal = el.props[prop];
                var compiledProperty = compileTemplate(propVal, this.$data);
                var directive = directives[prop];
                if(directive) {
                  el.node.removeAttribute(prop);
                  directive(el.node, compiledProperty, el);
                }

                if(!directive) el.node.setAttribute(prop, compiledProperty);
              }
            }

            this.build(el.children);
          }
        }

        /**
        * Initializes Moon
        */
        this.init = function() {
          this.log("======= Moon =======");
          if(_hooks.created) {
            _hooks.created();
          }
          this.compileComponents();
          this.createVirtualDOM(this.$el);
          this.build(this.$dom.children);
          if(_hooks.mounted) {
            _hooks.mounted();
          }
        }

        // Initialize 🎉
        this.init();
    }

    /**
    * Sets the Configuration of Moon
    * @param {Object} opts
    */
    Moon.config = function(opts) {
      if(opts.silent) {
        config.silent = opts.silent;
      }
    }

    /**
    * Runs an external Plugin
    * @param {Object} plugin
    */
    Moon.use = function(plugin) {
      plugin.init(Moon);
    }

    /**
    * Creates a Directive
    * @param {String} name
    * @param {Function} action
    */
    Moon.directive = function(name, action) {
      directives["m-" + name] = action;
    }

    /**
    * Creates a Component
    * @param {String} name
    * @param {Function} action
    */
    Moon.component = function(name, action) {
      components[name] = action;
    }

    /**
    * Makes an AJAX Request
    * @param {String} method
    * @param {String} url
    * @param {Object} params
    * @param {Function} cb
    */
    Moon.ajax = function(method, url, params, cb) {
      var xmlHttp = new XMLHttpRequest();
      method = method.toUpperCase();
      if(typeof params === "function") {
        cb = params;
      }
      var urlParams = "?";
      if(method === "POST") {
        http.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
        for(var param in params) {
          urlParams += param + "=" + params[param] + "&";
        }
      }
      xmlHttp.onreadystatechange = function() {
      if (xmlHttp.readyState == 4 && xmlHttp.status == 200)
        cb(JSON.parse(xmlHttp.responseText));
      }
      xmlHttp.open(method, url, true);
      xmlHttp.send(method === "POST" ? urlParams : null);
    }

    window.Moon = Moon;
})(window);
<|endoftext|>


<commit_before>var tape = require('tape')
var address = require('./')

tape('ipv4', function(t) {
  t.ok(/^\d+\.\d+\.\d+\.\d+$/.test(address()), 'looks like a ipv4')
  t.end()
})

tape('ipv4 #2', function(t) {
  t.ok(/^\d+\.\d+\.\d+\.\d+$/.test(address.ipv4()), 'looks like a ipv4')
  t.end()
})

tape('ipv6', function(t) {
  t.ok(/([0-f]*:)?([0-f]*:)?([0-f]*:)?([0-f]*:)?$/.test(address.ipv6()), 'looks like a ipv6')
  t.end()
})<commit_msg>Added a test passing the interface<commit_after>var tape = require('tape')
var address = require('./')

tape('ipv4', function(t) {
  t.ok(/^\d+\.\d+\.\d+\.\d+$/.test(address()), 'looks like a ipv4')
  t.end()
})

tape('ipv4 #2', function(t) {
  t.ok(/^\d+\.\d+\.\d+\.\d+$/.test(address.ipv4()), 'looks like a ipv4')
  t.end()
})

tape('ipv4 #3', function(t) {
  t.ok(/^\d+\.\d+\.\d+\.\d+$/.test(address.ipv4('lo')), 'looks like a ipv4')
  t.end()
})

tape('ipv6', function(t) {
  t.ok(/([0-f]*:)?([0-f]*:)?([0-f]*:)?([0-f]*:)?$/.test(address.ipv6()), 'looks like a ipv6')
  t.end()
})
<|endoftext|>


<commit_before>'use strict';

var sockjs = require('sockjs')
  , http = require('http');

//
// Setup a Sockjs server so we can listen for incoming connections and regular
// HTTP server to listen for incoming requests.
//
var realtime = sockjs.createServer()
  , server = http.createServer();

realtime.on('connection', function (socket) {
  socket.on('data', function echo(data) {
    socket.write(data);
  });
});

realtime.installHandlers(server, {
  prefix: '/test'
});

//
// Listen to the server.
//
server.listen(8123, function listening() {
  var SockJS = require('./')
    , socket = new SockJS('http://localhost:8123/test');

  socket.onopen = function onopen() {
    socket.send('foo');
  };

  socket.onmessage = function onmessage(evt) {
    if ('foo' === evt.data) return process.exit(0);

    console.error('Invalid message');
    process.exit(1);
  };

  setTimeout(function timeout() {
    console.error('timeout');

    process.exit(1);
  }, 1000);
});
<commit_msg>[test] Don't force the process to exit<commit_after>'use strict';

var sockjs = require('sockjs')
  , http = require('http')
  , SockJS = require('./');

//
// Setup a Sockjs server so we can listen for incoming connections and regular
// HTTP server to listen for incoming requests.
//
var realtime = sockjs.createServer()
  , server = http.createServer();

realtime.on('connection', function (socket) {
  socket.on('data', function echo(data) {
    socket.write(data);
  });
});

realtime.installHandlers(server, {
  prefix: '/test'
});

//
// Listen to the server.
//
server.listen(8123, function listening() {
  var socket = new SockJS('http://localhost:8123/test')
    , timeout;

  socket.onopen = function onopen() {
    socket.send('foo');
  };

  socket.onmessage = function onmessage(evt) {
    if ('foo' !== evt.data) throw new Error('Invalid message');

    clearTimeout(timeout);
    socket.close();
    server.close();
  };

  timeout = setTimeout(function timeout() {
    throw new Error('Timeout');
  }, 1000);
});
<|endoftext|>


<commit_before>(function () {

/*** Internal Variables ***/

  var win = window,
    doc = document,
    keypseudo = {
      action: function (pseudo, event) {
        return pseudo.value.match(/(\d+)/g).indexOf(String(event.keyCode)) > -1 == (pseudo.name == 'keypass');
      }
    },
    touchFilter = function (custom, event) {
      if (custom.listener.touched) return custom.listener.touched = false;
      else {
        if (event.type.match('touch')) custom.listener.touched = true;
      }
    },
    createFlowEvent = function (type) {
      var flow = type == 'over';
      return {
        base: 'OverflowEvent' in win ? 'overflowchanged' : type + 'flow',
        condition: function (custom, event) {
          event.flow = type;
          return event.type == (type + 'flow') ||
          ((event.orient === 0 && event.horizontalOverflow == flow) ||
          (event.orient == 1 && event.verticalOverflow == flow) ||
          (event.orient == 2 && event.horizontalOverflow == flow && event.verticalOverflow == flow));
        }
      };
    },
    prefix = (function () {
      var styles = win.getComputedStyle(doc.documentElement, ''),
        pre = (Array.prototype.slice
          .call(styles)
          .join('')
          .match(/-(moz|webkit|ms)-/) || (styles.OLink === '' && ['', 'o'])
        )[1],
        dom = ('WebKit|Moz|MS|O').match(new RegExp('(' + pre + ')', 'i'))[1];
      return {
        dom: dom,
        lowercase: pre,
        css: '-' + pre + '-',
        js: pre[0].toUpperCase() + pre.substr(1)
      };

    })(),
    matchSelector = Element.prototype.matchesSelector || Element.prototype[prefix.lowercase + 'MatchesSelector'];

/*** Internal Functions ***/

  // Mixins

  function mergeOne(source, key, current){
    var type = xtag.typeOf(current);
    if (type == 'object' && xtag.typeOf(source[key]) == 'object') xtag.merge(source[key], current);
    else source[key] = xtag.clone(current, type);
    return source;
  }

  function mergeMixin(type, mixin, option) {
    var original = {};
    for (var o in option) original[o.split(':')[0]] = true;
    for (var x in mixin) if (!original[x.split(':')[0]]) option[x] = mixin[x];
  }

  function applyMixins(tag) {
    tag.mixins.forEach(function (name) {
      var mixin = xtag.mixins[name];
      for (var type in mixin) {
        switch (type) {
          case 'lifecycle': case 'methods':
            mergeMixin(type, mixin[type], tag[type]);
            break;
          case 'accessors': case 'prototype':
            for (var z in mixin[type]) mergeMixin(z, mixin[type], tag.accessors);
            break;
          case 'events':
            break;
        }
      }
    });
    return tag;
  }

/*** X-Tag Object Definition ***/

  var xtag = {
    tags: {},
    defaultOptions: {
      pseudos: [],
      mixins: [],
      events: {},
      methods: {},
      accessors: {},
      lifecycle: {},
      'prototype': {
        xtag: {
          get: function(){
            return this.__xtag__ ? this.__xtag__ : (this.__xtag__ = { data: {} });
          }
        }
      }
    },
    register: function (name, options) {
      var _name = name.toLowerCase();
      var tag = xtag.tags[_name] = applyMixins(xtag.merge({}, xtag.defaultOptions, options));
      xtag.attributeSetters[_name] = {};

      for (var z in tag.events) tag.events[z] = xtag.parseEvent(z, tag.events[z]);
      for (var z in tag.lifecycle) tag.lifecycle[z.split(':')[0]] = xtag.applyPseudos(z, tag.lifecycle[z], tag.pseudos);
      for (var z in tag.methods) tag.prototype[z.split(':')[0]] = { value: xtag.applyPseudos(z, tag.methods[z], tag.pseudos) };

      for (var prop in tag.accessors) {
        tag.prototype[prop] = {};
        var accessor = tag.accessors[prop];
        for (var z in accessor) {
          var key = z.split(':'), type = key[0];
          if (type == 'get' || type == 'set') {
            key[0] = prop;
            tag.prototype[prop][type] = xtag.applyPseudos(key.join(':'), accessor[z], tag.pseudos);
          }
          else tag.prototype[prop][z] = accessor[z];
        }
      }

      var attributeChanged = tag.lifecycle.attributeChanged;
      tag.lifecycle.attributeChanged = function (attr, value, last, skip) {
        var setter = xtag.attributeSetters[_name][attr.toLowerCase()];
        if (!skip && setter) this[setter] = value;
        return attributeChanged ? attributeChanged.apply(this, xtag.toArray(arguments)) : null;
      };

      var created = tag.lifecycle.created;
      tag.lifecycle.created = function () {
        var element = this;
        tag.pseudos.forEach(function(obj){
          obj.onAdd.call(element, obj);
        });
        xtag.addEvents(this, tag.events);
        tag.mixins.forEach(function(mixin){
          if (xtag.mixins[mixin].events) xtag.addEvents(element, xtag.mixins[mixin].events);
        });
        return created ? created.apply(this, xtag.toArray(arguments)) : null;
      };

      var proto = doc.register(_name, {
        'prototype': 'nodeName' in tag.prototype ? tag.prototype : Object.create((win.HTMLSpanElement || win.HTMLElement).prototype, tag.prototype),
        'lifecycle':  tag.lifecycle
      });

      return proto;
    },

  /*** Exposed Variables ***/
    mixins: {},
    prefix: prefix,
    attributeSetters: {},
    captureEvents: ['focus', 'blur'],
    customEvents: {
      overflow: createFlowEvent('over'),
      underflow: createFlowEvent('under'),
      animationstart: {
        base: [
          'animationstart',
          'oAnimationStart',
          'MSAnimationStart',
          'webkitAnimationStart'
        ]
      },
      transitionend: {
        base: [
          'transitionend',
          'oTransitionEnd',
          'MSTransitionEnd',
          'webkitTransitionEnd'
        ]
      },
      tap: {
        base: ['click', 'touchend'],
        condition: touchFilter
      },
      tapstart: {
        base: ['mousedown', 'touchstart'],
        condition: touchFilter
      },
      tapend: {
        base: ['mouseup', 'touchend'],
        condition: touchFilter
      },
      tapenter: {
        base: ['mouseover', 'touchenter'],
        condition: touchFilter
      },
      tapleave: {
        base: ['mouseout', 'touchleave'],
        condition: touchFilter
      },
      tapmove: {
        base: ['mousemove', 'touchmove'],
        condition: touchFilter
      }
    },
    pseudos: {
      keypass: keypseudo,
      keyfail: keypseudo,
      delegate: {
        action: function (pseudo, event) {
          var target = xtag.query(this, pseudo.value).filter(function (node) {
            return node == event.target || node.contains ? node.contains(event.target) : false;
          })[0];
          return target ? pseudo.listener = pseudo.listener.bind(target) : false;
        }
      },
      preventable: {
        action: function (pseudo, event) {
          return !event.defaultPrevented;
        }
      },
      attribute: {
        onAdd: function(pseudo){
          var key = (pseudo.value || pseudo.key.split(':')[0]).toLowerCase();
          xtag.attributeSetters[this.nodeName.toLowerCase()][key] = pseudo.key.split(':')[0];
        },
        action: function (pseudo, value) {
          this.setAttribute(pseudo.value || pseudo.key.split(':')[0], value, true);
        }
      }
    },

  /*** Utilities ***/

    // JS Types

    wrap: function (original, fn) {
      return function () {
        var args = xtag.toArray(arguments),
          returned = original.apply(this, args);
        return returned === false ? false : fn.apply(this, typeof returned != 'undefined' ? xtag.toArray(returned) : args);
      };
    },

    merge: function(source, k, v){
      if (xtag.typeOf(k) == 'string') return mergeOne(source, k, v);
      for (var i = 1, l = arguments.length; i < l; i++){
        var object = arguments[i];
        for (var key in object) mergeOne(source, key, object[key]);
      }
      return source;
    },

    skipTransition: function(element, fn, bind){
      var duration = prefix.js + 'TransitionDuration';
      element.style[duration] = '0.001s';
      fn.call(bind);
      xtag.addEvent(element, 'transitionend', function(){
        element.style[duration] = '';
      });
    },

    matchSelector: function (element, selector) {
      return matchSelector.call(element, selector);
    },

    innerHTML: function (element, html) {
      element.innerHTML = html;
      if (xtag._polyfilled) {
        if (xtag.observerElement._observer) {
          xtag.parseMutations(xtag.observerElement, xtag.observerElement._observer.takeRecords());
        }
        else xtag._inserted(element);
      }
    },

    hasClass: function (element, klass) {
      return element.className.split(' ').indexOf(klass.trim())>-1;
    },

    addClass: function (element, klass) {
      var list = element.className.trim().split(' ');
      klass.trim().split(' ').forEach(function (name) {
        if (!~list.indexOf(name)) list.push(name);
      });
      element.className = list.join(' ').trim();
      return element;
    },

    removeClass: function (element, klass) {
      var classes = klass.trim().split(' ');
      element.className = element.className.trim().split(' ').filter(function (name) {
        return name && !~classes.indexOf(name);
      }).join(' ');
      return element;
    },
    toggleClass: function (element, klass) {
      return xtag[xtag.hasClass(element, klass) ? 'removeClass' : 'addClass'].call(null, element, klass);

    },
    query: function (element, selector) {
      return xtag.toArray(element.querySelectorAll(selector));
    },

    queryChildren: function (element, selector) {
      var id = element.id,
        guid = element.id = id || 'x_' + new Date().getTime(),
        attr = '#' + guid + ' > ';
      selector = attr + (selector + '').replace(',', ',' + attr, 'g');
      var result = element.parentNode.querySelectorAll(selector);
      if (!id) element.removeAttribute('id');
      return xtag.toArray(result);
    },

    createFragment: function (content) {
      var frag = doc.createDocumentFragment();
      if (content) {
        var div = frag.appendChild(doc.createElement('div')),
          nodes = xtag.toArray(content.nodeName ? arguments : !(div.innerHTML = content) || div.children),
          index = nodes.length;
        while (index--) frag.insertBefore(nodes[index], div);
        frag.removeChild(div);
      }
      return frag;
    },

  /*** Pseudos ***/

    applyPseudos: function(key, fn, element) {
      var listener = fn;
      if (key.match(':')) {
        var split = key.match(/(\w+(?:\([^\)]+\))?)/g),
            i = split.length;
        while (--i) {
          split[i].replace(/(\w*)(?:\(([^\)]*)\))?/, function (match, name, value) {
            var pseudo = xtag.pseudos[name];
                pseudo.key = key;
                pseudo.name = name;
                pseudo.value = value;
            if (!pseudo) throw "pseudo not found: " + name;
            var last = listener;
            listener = function(){
              var args = xtag.toArray(arguments),
                  obj = {
                    key: key,
                    name: name,
                    value: value,
                    listener: last
                  };
              if (pseudo.action.apply(this, [obj].concat(args)) === false) return false;
              return obj.listener.apply(this, args);
            };
            if (element && pseudo.onAdd) {
              element.getAttribute ? pseudo.onAdd.call(element, pseudo) : element.push(pseudo);
            }
          });
        }
      }
      return listener;
    },

  /*** Events ***/

    parseEvent: function(type, fn) {
      var pseudos = type.split(':'),
        noop = function(){},
        key = pseudos.shift(),
        event = xtag.merge({
          base: key,
          pseudos: '',
          _pseudos: [],
          onAdd: noop,
          onRemove: noop,
          condition: noop
        }, xtag.customEvents[key] || {});
      event.type = key + (event.pseudos.length ? ':' + event.pseudos : '') + (pseudos.length ? ':' + pseudos.join(':') : '');
      if (fn) {
        var chained = xtag.applyPseudos(event.type, fn, event._pseudos);
        event.listener = function(){
          var args = xtag.toArray(arguments);
          if (event.condition.apply(this, [event].concat(args)) === false) return false;
          return chained.apply(this, args);
        };
      }
      return event;
    },

    addEvent: function (element, type, fn) {
      var event = (typeof fn == 'function') ? xtag.parseEvent(type, fn) : fn;
      event._pseudos.forEach(function(obj){
        obj.onAdd.call(element, obj);
      });
      event.onAdd.call(element, event, event.listener);
      xtag.toArray(event.base).forEach(function (name) {
        element.addEventListener(name, event.listener, xtag.captureEvents.indexOf(name) > -1);
      });
      return event.listener;
    },

    addEvents: function (element, events) {
      for (var z in events) xtag.addEvent(element, z, events[z]);
    },

    removeEvent: function (element, type, fn) {
      var event = xtag.parseEvent(type);
      event.onRemove.call(element, event, fn);
      xtag.removePseudos(element, event.type, fn);
      xtag.toArray(event.base).forEach(function (name) {
        element.removeEventListener(name, fn);
      });
    }
  };

  xtag.typeOf = doc.register.__polyfill__.typeOf;
  xtag.clone = doc.register.__polyfill__.clone;
  xtag.merge(xtag, doc.register.__polyfill__);

  if (typeof define == 'function' && define.amd) define(xtag);
  else win.xtag = xtag;

})();
<commit_msg>added a 'removeEvents' method, and a return object to addEvent<commit_after>(function () {

/*** Internal Variables ***/

  var win = window,
    doc = document,
    keypseudo = {
      action: function (pseudo, event) {
        return pseudo.value.match(/(\d+)/g).indexOf(String(event.keyCode)) > -1 == (pseudo.name == 'keypass');
      }
    },
    touchFilter = function (custom, event) {
      if (custom.listener.touched) return custom.listener.touched = false;
      else {
        if (event.type.match('touch')) custom.listener.touched = true;
      }
    },
    createFlowEvent = function (type) {
      var flow = type == 'over';
      return {
        base: 'OverflowEvent' in win ? 'overflowchanged' : type + 'flow',
        condition: function (custom, event) {
          event.flow = type;
          return event.type == (type + 'flow') ||
          ((event.orient === 0 && event.horizontalOverflow == flow) ||
          (event.orient == 1 && event.verticalOverflow == flow) ||
          (event.orient == 2 && event.horizontalOverflow == flow && event.verticalOverflow == flow));
        }
      };
    },
    prefix = (function () {
      var styles = win.getComputedStyle(doc.documentElement, ''),
        pre = (Array.prototype.slice
          .call(styles)
          .join('')
          .match(/-(moz|webkit|ms)-/) || (styles.OLink === '' && ['', 'o'])
        )[1],
        dom = ('WebKit|Moz|MS|O').match(new RegExp('(' + pre + ')', 'i'))[1];
      return {
        dom: dom,
        lowercase: pre,
        css: '-' + pre + '-',
        js: pre[0].toUpperCase() + pre.substr(1)
      };

    })(),
    matchSelector = Element.prototype.matchesSelector || Element.prototype[prefix.lowercase + 'MatchesSelector'];

/*** Internal Functions ***/

  // Mixins

  function mergeOne(source, key, current){
    var type = xtag.typeOf(current);
    if (type == 'object' && xtag.typeOf(source[key]) == 'object') xtag.merge(source[key], current);
    else source[key] = xtag.clone(current, type);
    return source;
  }

  function mergeMixin(type, mixin, option) {
    var original = {};
    for (var o in option) original[o.split(':')[0]] = true;
    for (var x in mixin) if (!original[x.split(':')[0]]) option[x] = mixin[x];
  }

  function applyMixins(tag) {
    tag.mixins.forEach(function (name) {
      var mixin = xtag.mixins[name];
      for (var type in mixin) {
        switch (type) {
          case 'lifecycle': case 'methods':
            mergeMixin(type, mixin[type], tag[type]);
            break;
          case 'accessors': case 'prototype':
            for (var z in mixin[type]) mergeMixin(z, mixin[type], tag.accessors);
            break;
          case 'events':
            break;
        }
      }
    });
    return tag;
  }

/*** X-Tag Object Definition ***/

  var xtag = {
    tags: {},
    defaultOptions: {
      pseudos: [],
      mixins: [],
      events: {},
      methods: {},
      accessors: {},
      lifecycle: {},
      'prototype': {
        xtag: {
          get: function(){
            return this.__xtag__ ? this.__xtag__ : (this.__xtag__ = { data: {} });
          }
        }
      }
    },
    register: function (name, options) {
      var _name = name.toLowerCase();
      var tag = xtag.tags[_name] = applyMixins(xtag.merge({}, xtag.defaultOptions, options));
      xtag.attributeSetters[_name] = {};

      for (var z in tag.events) tag.events[z] = xtag.parseEvent(z, tag.events[z]);
      for (var z in tag.lifecycle) tag.lifecycle[z.split(':')[0]] = xtag.applyPseudos(z, tag.lifecycle[z], tag.pseudos);
      for (var z in tag.methods) tag.prototype[z.split(':')[0]] = { value: xtag.applyPseudos(z, tag.methods[z], tag.pseudos) };

      for (var prop in tag.accessors) {
        tag.prototype[prop] = {};
        var accessor = tag.accessors[prop];
        for (var z in accessor) {
          var key = z.split(':'), type = key[0];
          if (type == 'get' || type == 'set') {
            key[0] = prop;
            tag.prototype[prop][type] = xtag.applyPseudos(key.join(':'), accessor[z], tag.pseudos);
          }
          else tag.prototype[prop][z] = accessor[z];
        }
      }

      var attributeChanged = tag.lifecycle.attributeChanged;
      tag.lifecycle.attributeChanged = function (attr, value, last, skip) {
        var setter = xtag.attributeSetters[_name][attr.toLowerCase()];
        if (!skip && setter) this[setter] = value;
        return attributeChanged ? attributeChanged.apply(this, xtag.toArray(arguments)) : null;
      };

      var created = tag.lifecycle.created;
      tag.lifecycle.created = function () {
        var element = this;
        tag.pseudos.forEach(function(obj){
          obj.onAdd.call(element, obj);
        });
        xtag.addEvents(this, tag.events);
        tag.mixins.forEach(function(mixin){
          if (xtag.mixins[mixin].events) xtag.addEvents(element, xtag.mixins[mixin].events);
        });
        return created ? created.apply(this, xtag.toArray(arguments)) : null;
      };

      var proto = doc.register(_name, {
        'prototype': 'nodeName' in tag.prototype ? tag.prototype : Object.create((win.HTMLSpanElement || win.HTMLElement).prototype, tag.prototype),
        'lifecycle':  tag.lifecycle
      });

      return proto;
    },

  /*** Exposed Variables ***/
    mixins: {},
    prefix: prefix,
    attributeSetters: {},
    captureEvents: ['focus', 'blur'],
    customEvents: {
      overflow: createFlowEvent('over'),
      underflow: createFlowEvent('under'),
      animationstart: {
        base: [
          'animationstart',
          'oAnimationStart',
          'MSAnimationStart',
          'webkitAnimationStart'
        ]
      },
      transitionend: {
        base: [
          'transitionend',
          'oTransitionEnd',
          'MSTransitionEnd',
          'webkitTransitionEnd'
        ]
      },
      tap: {
        base: ['click', 'touchend'],
        condition: touchFilter
      },
      tapstart: {
        base: ['mousedown', 'touchstart'],
        condition: touchFilter
      },
      tapend: {
        base: ['mouseup', 'touchend'],
        condition: touchFilter
      },
      tapenter: {
        base: ['mouseover', 'touchenter'],
        condition: touchFilter
      },
      tapleave: {
        base: ['mouseout', 'touchleave'],
        condition: touchFilter
      },
      tapmove: {
        base: ['mousemove', 'touchmove'],
        condition: touchFilter
      }
    },
    pseudos: {
      keypass: keypseudo,
      keyfail: keypseudo,
      delegate: {
        action: function (pseudo, event) {
          var target = xtag.query(this, pseudo.value).filter(function (node) {
            return node == event.target || node.contains ? node.contains(event.target) : false;
          })[0];
          return target ? pseudo.listener = pseudo.listener.bind(target) : false;
        }
      },
      preventable: {
        action: function (pseudo, event) {
          return !event.defaultPrevented;
        }
      },
      attribute: {
        onAdd: function(pseudo){
          var key = (pseudo.value || pseudo.key.split(':')[0]).toLowerCase();
          xtag.attributeSetters[this.nodeName.toLowerCase()][key] = pseudo.key.split(':')[0];
        },
        action: function (pseudo, value) {
          this.setAttribute(pseudo.value || pseudo.key.split(':')[0], value, true);
        }
      }
    },

  /*** Utilities ***/

    // JS Types

    wrap: function (original, fn) {
      return function () {
        var args = xtag.toArray(arguments),
          returned = original.apply(this, args);
        return returned === false ? false : fn.apply(this, typeof returned != 'undefined' ? xtag.toArray(returned) : args);
      };
    },

    merge: function(source, k, v){
      if (xtag.typeOf(k) == 'string') return mergeOne(source, k, v);
      for (var i = 1, l = arguments.length; i < l; i++){
        var object = arguments[i];
        for (var key in object) mergeOne(source, key, object[key]);
      }
      return source;
    },

    skipTransition: function(element, fn, bind){
      var duration = prefix.js + 'TransitionDuration';
      element.style[duration] = '0.001s';
      fn.call(bind);
      xtag.addEvent(element, 'transitionend', function(){
        element.style[duration] = '';
      });
    },

    matchSelector: function (element, selector) {
      return matchSelector.call(element, selector);
    },

    innerHTML: function (element, html) {
      element.innerHTML = html;
      if (xtag._polyfilled) {
        if (xtag.observerElement._observer) {
          xtag.parseMutations(xtag.observerElement, xtag.observerElement._observer.takeRecords());
        }
        else xtag._inserted(element);
      }
    },

    hasClass: function (element, klass) {
      return element.className.split(' ').indexOf(klass.trim())>-1;
    },

    addClass: function (element, klass) {
      var list = element.className.trim().split(' ');
      klass.trim().split(' ').forEach(function (name) {
        if (!~list.indexOf(name)) list.push(name);
      });
      element.className = list.join(' ').trim();
      return element;
    },

    removeClass: function (element, klass) {
      var classes = klass.trim().split(' ');
      element.className = element.className.trim().split(' ').filter(function (name) {
        return name && !~classes.indexOf(name);
      }).join(' ');
      return element;
    },
    toggleClass: function (element, klass) {
      return xtag[xtag.hasClass(element, klass) ? 'removeClass' : 'addClass'].call(null, element, klass);

    },
    query: function (element, selector) {
      return xtag.toArray(element.querySelectorAll(selector));
    },

    queryChildren: function (element, selector) {
      var id = element.id,
        guid = element.id = id || 'x_' + new Date().getTime(),
        attr = '#' + guid + ' > ';
      selector = attr + (selector + '').replace(',', ',' + attr, 'g');
      var result = element.parentNode.querySelectorAll(selector);
      if (!id) element.removeAttribute('id');
      return xtag.toArray(result);
    },

    createFragment: function (content) {
      var frag = doc.createDocumentFragment();
      if (content) {
        var div = frag.appendChild(doc.createElement('div')),
          nodes = xtag.toArray(content.nodeName ? arguments : !(div.innerHTML = content) || div.children),
          index = nodes.length;
        while (index--) frag.insertBefore(nodes[index], div);
        frag.removeChild(div);
      }
      return frag;
    },

  /*** Pseudos ***/

    applyPseudos: function(key, fn, element) {
      var listener = fn,
          pseudos = {};
      if (key.match(':')) {
        var split = key.match(/(\w+(?:\([^\)]+\))?)/g),
            i = split.length;
        while (--i) {
          split[i].replace(/(\w*)(?:\(([^\)]*)\))?/, function (match, name, value) {
            var pseudo = pseudos[i] = Object.create(xtag.pseudos[name]);
                pseudo.key = key;
                pseudo.name = name;
                pseudo.value = value;
            if (!pseudo) throw "pseudo not found: " + name;
            var last = listener;
            listener = function(){
              var args = xtag.toArray(arguments),
                  obj = {
                    key: key,
                    name: name,
                    value: value,
                    listener: last
                  };
              if (pseudo.action && pseudo.action.apply(this, [obj].concat(args)) === false) return false;
              return obj.listener.apply(this, args);
            };
            if (element && pseudo.onAdd) {
              element.getAttribute ? pseudo.onAdd.call(element, pseudo) : element.push(pseudo);
            }
          });
        }
      }
      for (var z in pseudos) {
        if (pseudos[z].onWrap) listener = pseudos[z].onWrap(listener, pseudos[z]);
      }
      return listener;
    },

  /*** Events ***/

    parseEvent: function(type, fn) {
      var pseudos = type.split(':'),
        noop = function(){},
        key = pseudos.shift(),
        event = xtag.merge({
          base: key,
          pseudos: '',
          _pseudos: [],
          onAdd: noop,
          onRemove: noop,
          condition: noop
        }, xtag.customEvents[key] || {});
      event.type = key + (event.pseudos.length ? ':' + event.pseudos : '') + (pseudos.length ? ':' + pseudos.join(':') : '');
      if (fn) {
        var chained = xtag.applyPseudos(event.type, fn, event._pseudos);
        event.listener = function(){
          var args = xtag.toArray(arguments);
          if (event.condition.apply(this, [event].concat(args)) === false) return false;
          return chained.apply(this, args);
        };
      }
      return event;
    },

    addEvent: function (element, type, fn) {
      var event = (typeof fn == 'function') ? xtag.parseEvent(type, fn) : fn;
      event._pseudos.forEach(function(obj){
        obj.onAdd.call(element, obj);
      });
      event.onAdd.call(element, event, event.listener);
      xtag.toArray(event.base).forEach(function (name) {
        element.addEventListener(name, event.listener, xtag.captureEvents.indexOf(name) > -1);
      });
      return event.listener;
    },

    addEvents: function (element, events) {
      var listeners = {};
      for (var z in events) {
        listeners[z] = xtag.addEvent(element, z, events[z]);
      }
      return listeners;
    },

    removeEvent: function (element, type, fn) {
      var event = xtag.parseEvent(type);
      event.onRemove.call(element, event, fn);
      xtag.removePseudos(element, event.type, fn);
      xtag.toArray(event.base).forEach(function (name) {
        element.removeEventListener(name, fn);
      });
    },

    removeEvents: function(element, listeners){
      for (var z in listeners) xtag.removeEvent(element, z, listeners[z]);
    }

  };

  xtag.typeOf = doc.register.__polyfill__.typeOf;
  xtag.clone = doc.register.__polyfill__.clone;
  xtag.merge(xtag, doc.register.__polyfill__);

  if (typeof define == 'function' && define.amd) define(xtag);
  else win.xtag = xtag;

})();
<|endoftext|>


<commit_before>/*
Name:         openkvk - test.js
Description:  Test script for openkvk.js
Source:       https://github.com/fvdm/nodejs-openkvk
Feedback:     https://github.com/fvdm/nodejs-openkvk/issues
License:      Public Domain / Unlicense (see LICENSE file)
*/

const dotest = require ('dotest');
const app = require ('./');

// Setup
const timeout = process.env.testTimeout || 5000;

// Tests
dotest.add ('Interface', test => {
  test ()
    .isFunction ('fail', 'exports', app)
    .done ()
  ;
});

dotest.add ('Error: no results', async test => {
  let error;
  let data;

  try {
    data = await app ({
      entity: 'software',
      country: 'NL',
      term: 'this_is_hopefully_not_an_existing_app_in_the_app_store',
      limit: 1,
      price: 0,
      timeout,
    });
  }
  catch (err) {
    error = err;
  }

  test ()
    .isError ('fail', 'error', error)
    .isExactly ('fail', 'error.message', error && error.message, 'no results')
    .isUndefined ('fail', 'data', data)
    .done ()
  ;
});

dotest.add ('Error: request error', async test => {
  let error;
  let data;

  try {
    data = await app ({ timeout: 1 });
  }
  catch (err) {
    error = err;
  }

  test ()
    .isError ('fail', 'error', error)
    .isExactly ('fail', 'error.code', error && error.code, 'TIMEOUT')
    .isUndefined ('fail', 'data', data)
    .done ()
  ;
});

dotest.add ('Lookup by ID', async test => {
  let error;
  let data;

  try {
    data = await app ({
      id: 512939461,
      timeout,
    });
  }
  catch (err) {
    error = err;
  }

  test (error)
    .isObject ('fail', 'data', data)
    .isExactly ('fail', 'data.trackId', data && data.trackId, 512939461)
    .done ()
  ;
});

dotest.add ('Search by term', async test => {
  let error;
  let data;
  let item;

  try {
    data = await app ({
      entity: 'software',
      country: 'NL',
      term: 'github',
      limit: 1,
      price: 0,
      userAgent: 'test.js',
      timeout,
    });

    item = data.results && data.results [0];
  }
  catch (err) {
    error = err;
  }

  test (error)
    .isObject ('fail', 'data', data)
    .isExactly ('fail', 'data.resultCount', data && data.resultCount, 1)
    .isArray ('fail', 'data.results', data && data.results)
    .isNotEmpty ('fail', 'data.results', data && data.results)
    .isObject ('fail', 'data.results[0]', item)
    .isExactly ('fail', 'data.results[0].kind', item && item.kind, 'software')
    .done ()
  ;
});

// Start the tests
dotest.run ();
<commit_msg>Test: Check error value<commit_after>/*
Name:         openkvk - test.js
Description:  Test script for openkvk.js
Source:       https://github.com/fvdm/nodejs-openkvk
Feedback:     https://github.com/fvdm/nodejs-openkvk/issues
License:      Public Domain / Unlicense (see LICENSE file)
*/

const dotest = require ('dotest');
const app = require ('./');

// Setup
const timeout = process.env.testTimeout || 5000;

// Tests
dotest.add ('Interface', test => {
  test ()
    .isFunction ('fail', 'exports', app)
    .done ()
  ;
});

dotest.add ('Error: no results', async test => {
  let error;
  let data;

  try {
    data = await app ({
      entity: 'software',
      country: 'NL',
      term: 'this_is_hopefully_not_an_existing_app_in_the_app_store',
      limit: 1,
      price: 0,
      timeout,
    });
  }
  catch (err) {
    error = err;
  }

  test ()
    .isError ('fail', 'error', error)
    .isExactly ('fail', 'error.message', error && error.message, 'no results')
    .isUndefined ('fail', 'data', data)
    .done ()
  ;
});

dotest.add ('Error: request error', async test => {
  let error;
  let data;

  try {
    data = await app ({ timeout: 1 });
  }
  catch (err) {
    error = err;
  }

  test ()
    .isError ('fail', 'error', error)
    .isExactly ('fail', 'error.code', error && error.code, 'TIMEOUT')
    .isUndefined ('fail', 'data', data)
    .done ()
  ;
});

dotest.add ('Lookup by ID', async test => {
  let error;
  let data;

  try {
    data = await app ({
      id: 512939461,
      timeout,
    });
  }
  catch (err) {
    error = err;
  }

  test (error)
    .isObject ('fail', 'data', data)
    .isExactly ('fail', 'data.trackId', data && data.trackId, 512939461)
    .isUndefined ('fail', 'error', error)
    .done ()
  ;
});

dotest.add ('Search by term', async test => {
  let error;
  let data;
  let item;

  try {
    data = await app ({
      entity: 'software',
      country: 'NL',
      term: 'github',
      limit: 1,
      price: 0,
      userAgent: 'test.js',
      timeout,
    });

    item = data.results && data.results [0];
  }
  catch (err) {
    error = err;
  }

  test (error)
    .isObject ('fail', 'data', data)
    .isExactly ('fail', 'data.resultCount', data && data.resultCount, 1)
    .isArray ('fail', 'data.results', data && data.results)
    .isNotEmpty ('fail', 'data.results', data && data.results)
    .isObject ('fail', 'data.results[0]', item)
    .isExactly ('fail', 'data.results[0].kind', item && item.kind, 'software')
    .isUndefined ('fail', 'error', error)
    .done ()
  ;
});

// Start the tests
dotest.run ();
<|endoftext|>


<commit_before>/**
 * User: Martin Martimeo
 * Date: 08.08.13
 * Time: 14:48
 *
 * Core Lib
 */

require(["jquery", "underscore", "backbone"],function ($, _, Backbone) {
    var self = this.Tornado || {};
    var Tornado = this.Tornado = self;

    /**
     * Operator defined by restless
     *
     * @TODO Add Tornado Restless Operators
     */
    Tornado.Operator = {
        equals: ["==", "eq", "equals", "equals_to"],
        unequals: ["!=", "ne", "neq", "does_not_equal", "not_equal_to"],
        gt: [">", "gt"],
        lt: ["<", "lt"],
        gte: [">=", "ge", "gte", "geq"],
        lte: ["<=", "le", "lte", "leq"],
        element_of: ["in", "element_of"],
        not_element_of: ["not_in", "not_element_of"],
        is_null: ["is_null"],
        is_not_null: ["is_not_null"],
        like: ["like"],
        has: ["has"],
        any: ["any"]
    };

    /**
     * If set, all sync calls will be enriched with this token
     */
    Tornado.xsrf_token = null;

    /**
     * Enriched Backbone model with a lot of information about the sqlalchemy model
     *
     * @type Tornado.Model
     */
    Tornado.Model = Backbone.Model.extend({

        /**
         * Schema for use with backbone-forms
         */
        schema: {},

        /**
         * List of default values
         */
        defaults: {},

        /**
         * Collection URL entry point
         */
        urlRoot: null,

        /**
         * Either idAttribute (if one pk) or idAttributes (more than one pk) for referencing the model
         */
        idAttribute: null,
        idAttributes: null,

        /**
         * Information about the defined relations for the model
         */
        relations: [],

        /**
         * Bunch of information about the model
         */
        columnAttributes: [], //! All columns
        relationAttributes: [], //! All relations
        readonlyAttributes: [], //! Columns with 'readonly' in column.info

        /**
         * Guess the type based on the schema
         *
         * @param attribute
         */
        is_numeric: function (attribute) {
            if (this.schema.hasOwnProperty(attribute)) {
                if (this.schema[attribute].type == "Number") {
                    return true;
                }
                if (this.schema[attribute].type == "Text" && this.schema[attribute].dataType == "number") {
                    return true;
                }
            }
            return false;
        },

        /**
         * Guess the type based on the schema
         *
         * @param attribute
         */
        is_datetime: function (attribute) {
            if (this.schema.hasOwnProperty(attribute)) {
                if (this.schema[attribute].type == "DateTime") {
                    return true;
                }
                if (this.schema[attribute].type == "Text" && this.schema[attribute].dataType == "datetime") {
                    return true;
                }
            }
            return false;
        },

        /**
         * Resolve all attributes that are datetimes
         *
         * @returns {*}
         */
        getDatetimeAttributes: function () {
            if (this.hasOwnProperty("datetimeAttributes")) {
                return this.datetimeAttributes;
            }
            var i, l, attribute, attributes = [];
            for (i = 0, l = this.columnAttributes.length; i < l; i++) {
                attribute = this.columnAttributes[i];
                if (this.is_datetime(attribute)) {
                    attributes.push(attribute);
                }
            }
            this.datetimeAttributes = attributes;
            return attributes;
        },

        /**
         * Overwriten parse to support datetime strings
         * @param response
         * @param options
         * @returns attributes
         */
        parse: function (response, options) {
            var attributes = Backbone.Model.prototype.parse.call(this, response, options);

            var i, l, attribute;
            for (i = 0, l = this.getDatetimeAttributes().length; i < l; i++) {
                attribute = this.datetimeAttributes[i];
                attributes[attribute] = new Date(attributes[attribute])
            }
            return attributes;
        },

        /**
         * Sync method with adds xsrf_token if available
         *
         * @param method
         * @param model
         * @param options
         * @returns {*}
         */
        sync: function (method, model, options) {
            if (Tornado.xsrf_token) {
                options = options || {};
                options.headers = options.headers || {};
                options.headers['X-XSRFToken'] = Tornado.xsrf_token;
            }
            return Backbone.sync(method, model, options);
        },

        /**
         * If the model provides a __str__ attribute
         * this will be used to displays in like backbone.forms
         */
        toString: function () {
            var rtn = this.get('__str__');
            if (rtn) {
                return rtn;
            }
            return "[object Tornado.Model at " + this.url() + "]";
        }

    });

    Tornado.Collection = Backbone.Collection.extend({

        // Objects on page
        page: 0,
        page_length: 25,
        num_results: null,

        /**
         * Is this Collection fully loaded?
         */
        hasMore: function () {
            return this.num_results < this.models.length;
        },

        /**
         * Multiple call of fetch will increase in page count
         */
        fetch: function (options) {
            var collection = this;

            options = options ? _.clone(options) : {};
            options.data = options.data ? options.data : {};
            if (this.page_length) {
                options.data["results_per_page"] = this.page_length;
            }
            options.data["page"] = options.reset || !collection.page ? undefined : collection.page + 1;

            return Backbone.Collection.prototype.fetch.call(collection, options);
        },

        // parse data from server
        // This is specific overwritten to work with flask-restless / tornado-restless
        parse: function (data) {
            var objects = data.objects || data;

            this.num_results = data.num_results || data.length;
            this.page = data.page || 1;
            this.total_pages = data.total_pages || 0;
            if (this.num_results < this.models.length + objects.length) {
                this.trigger("tb.pagination", "load");
            } else {
                this.trigger("tb.pagination", "complete");
            }

            return objects;
        }
    });

    /**
     * A FilteredCollection
     *
     * It preserves a list of filters that are maintained for all queries
     *
     * @type Tornado.FilteredCollection
     */
    Tornado.FilteredCollection = Tornado.Collection.extend({

        /**
         * List of applied filters
         */
        filters: [],

        /**
         * Apply a filter
         *
         * filter: [list|object]: The filter
         * [options]: update: Update an existing filter
         *            nofetch: Do not fetch collection (useful for bulk updating)
         */
        filterBy: function (filter, options) {
            var collection = this;

            if (_.isArray(filter)) {
                if (filter.length > 2) {
                    filter = {'name': filter[0], 'op': filter[1], 'val': filter[2]};
                } else {
                    filter = {'name': filter[0], 'val': filter[2]};
                }
            } else if (_.isString(filter)) {
                filter = {'name': arguments[0], 'op': arguments[1], 'val': arguments[2]};
                options = arguments[3];
            }

            _.defaults(filter, {'op': 'eq'});

            if (options.update) {
                collection.filters = _.reject(collection.filters, function (f) {
                    return f.name == filter['name']
                });
            }
            collection.filters.push(filter);
            if (!options.nofetch) {
                collection.fetch({reset: true});
            }
        },

        /**
         * Remove a filter
         *
         * filter: [list|object|string]: The filter
         * [options]: nofetch: Do not fetch collection (useful for bulk updating)
         */
        removeFilter: function (filter, options) {
            var collection = this;

            if (_.isString(filter)) {
                collection.filters = _.reject(collection.filters, function (f) {
                    return f.name == filter
                });
            } else {
                collection.filters = _.reject(collection.filters, function (f) {
                    return f == filter
                });
            }
            if (!options.nofetch) {
                collection.fetch({reset: true});
            }
        },

        /**
         * Augment Fetch with all information
         */
        fetch: function (options) {
            var collection = this;

            options = options ? _.clone(options) : {};
            options.data = options.data ? options.data : {};
            options.data["q"] = JSON.stringify({"filters": collection.filters});

            return Tornado.Collection.prototype.fetch.call(collection, options);
        }

    });

    return Tornado;
}).call(window);
<commit_msg>Use server page_length per default instead of always passing it by default<commit_after>/**
 * User: Martin Martimeo
 * Date: 08.08.13
 * Time: 14:48
 *
 * Core Lib
 */

require(["jquery", "underscore", "backbone"],function ($, _, Backbone) {
    var self = this.Tornado || {};
    var Tornado = this.Tornado = self;

    /**
     * Operator defined by restless
     *
     * @TODO Add Tornado Restless Operators
     */
    Tornado.Operator = {
        equals: ["==", "eq", "equals", "equals_to"],
        unequals: ["!=", "ne", "neq", "does_not_equal", "not_equal_to"],
        gt: [">", "gt"],
        lt: ["<", "lt"],
        gte: [">=", "ge", "gte", "geq"],
        lte: ["<=", "le", "lte", "leq"],
        element_of: ["in", "element_of"],
        not_element_of: ["not_in", "not_element_of"],
        is_null: ["is_null"],
        is_not_null: ["is_not_null"],
        like: ["like"],
        has: ["has"],
        any: ["any"]
    };

    /**
     * If set, all sync calls will be enriched with this token
     */
    Tornado.xsrf_token = null;

    /**
     * Enriched Backbone model with a lot of information about the sqlalchemy model
     *
     * @type Tornado.Model
     */
    Tornado.Model = Backbone.Model.extend({

        /**
         * Schema for use with backbone-forms
         */
        schema: {},

        /**
         * List of default values
         */
        defaults: {},

        /**
         * Collection URL entry point
         */
        urlRoot: null,

        /**
         * Either idAttribute (if one pk) or idAttributes (more than one pk) for referencing the model
         */
        idAttribute: null,
        idAttributes: null,

        /**
         * Information about the defined relations for the model
         */
        relations: [],

        /**
         * Bunch of information about the model
         */
        columnAttributes: [], //! All columns
        relationAttributes: [], //! All relations
        readonlyAttributes: [], //! Columns with 'readonly' in column.info

        /**
         * Guess the type based on the schema
         *
         * @param attribute
         */
        is_numeric: function (attribute) {
            if (this.schema.hasOwnProperty(attribute)) {
                if (this.schema[attribute].type == "Number") {
                    return true;
                }
                if (this.schema[attribute].type == "Text" && this.schema[attribute].dataType == "number") {
                    return true;
                }
            }
            return false;
        },

        /**
         * Guess the type based on the schema
         *
         * @param attribute
         */
        is_datetime: function (attribute) {
            if (this.schema.hasOwnProperty(attribute)) {
                if (this.schema[attribute].type == "DateTime") {
                    return true;
                }
                if (this.schema[attribute].type == "Text" && this.schema[attribute].dataType == "datetime") {
                    return true;
                }
            }
            return false;
        },

        /**
         * Resolve all attributes that are datetimes
         *
         * @returns {*}
         */
        getDatetimeAttributes: function () {
            if (this.hasOwnProperty("datetimeAttributes")) {
                return this.datetimeAttributes;
            }
            var i, l, attribute, attributes = [];
            for (i = 0, l = this.columnAttributes.length; i < l; i++) {
                attribute = this.columnAttributes[i];
                if (this.is_datetime(attribute)) {
                    attributes.push(attribute);
                }
            }
            this.datetimeAttributes = attributes;
            return attributes;
        },

        /**
         * Overwriten parse to support datetime strings
         * @param response
         * @param options
         * @returns attributes
         */
        parse: function (response, options) {
            var attributes = Backbone.Model.prototype.parse.call(this, response, options);

            var i, l, attribute;
            for (i = 0, l = this.getDatetimeAttributes().length; i < l; i++) {
                attribute = this.datetimeAttributes[i];
                attributes[attribute] = new Date(attributes[attribute])
            }
            return attributes;
        },

        /**
         * Sync method with adds xsrf_token if available
         *
         * @param method
         * @param model
         * @param options
         * @returns {*}
         */
        sync: function (method, model, options) {
            if (Tornado.xsrf_token) {
                options = options || {};
                options.headers = options.headers || {};
                options.headers['X-XSRFToken'] = Tornado.xsrf_token;
            }
            return Backbone.sync(method, model, options);
        },

        /**
         * If the model provides a __str__ attribute
         * this will be used to displays in like backbone.forms
         */
        toString: function () {
            var rtn = this.get('__str__');
            if (rtn) {
                return rtn;
            }
            return "[object Tornado.Model at " + this.url() + "]";
        }

    });

    Tornado.Collection = Backbone.Collection.extend({

        // Objects on page
        page: 0,
        page_length: null,
        num_results: null,

        /**
         * Is this Collection fully loaded?
         */
        hasMore: function () {
            return this.num_results < this.models.length;
        },

        /**
         * Multiple call of fetch will increase in page count
         */
        fetch: function (options) {
            var collection = this;

            options = options ? _.clone(options) : {};
            options.data = options.data ? options.data : {};
            if (this.page_length) {
                options.data["results_per_page"] = this.page_length;
            }
            options.data["page"] = options.reset || !collection.page ? undefined : collection.page + 1;

            return Backbone.Collection.prototype.fetch.call(collection, options);
        },

        // parse data from server
        // This is specific overwritten to work with flask-restless / tornado-restless
        parse: function (data) {
            var objects = data.objects || data;

            this.num_results = data.num_results || data.length;
            this.page = data.page || 1;
            this.total_pages = data.total_pages || 0;
            if (this.num_results < this.models.length + objects.length) {
                this.trigger("tb.pagination", "load");
            } else {
                this.trigger("tb.pagination", "complete");
            }

            return objects;
        }
    });

    /**
     * A FilteredCollection
     *
     * It preserves a list of filters that are maintained for all queries
     *
     * @type Tornado.FilteredCollection
     */
    Tornado.FilteredCollection = Tornado.Collection.extend({

        /**
         * List of applied filters
         */
        filters: [],

        /**
         * Apply a filter
         *
         * filter: [list|object]: The filter
         * [options]: update: Update an existing filter
         *            nofetch: Do not fetch collection (useful for bulk updating)
         */
        filterBy: function (filter, options) {
            var collection = this;

            if (_.isArray(filter)) {
                if (filter.length > 2) {
                    filter = {'name': filter[0], 'op': filter[1], 'val': filter[2]};
                } else {
                    filter = {'name': filter[0], 'val': filter[2]};
                }
            } else if (_.isString(filter)) {
                filter = {'name': arguments[0], 'op': arguments[1], 'val': arguments[2]};
                options = arguments[3];
            }

            _.defaults(filter, {'op': 'eq'});

            if (options.update) {
                collection.filters = _.reject(collection.filters, function (f) {
                    return f.name == filter['name']
                });
            }
            collection.filters.push(filter);
            if (!options.nofetch) {
                collection.fetch({reset: true});
            }
        },

        /**
         * Remove a filter
         *
         * filter: [list|object|string]: The filter
         * [options]: nofetch: Do not fetch collection (useful for bulk updating)
         */
        removeFilter: function (filter, options) {
            var collection = this;

            if (_.isString(filter)) {
                collection.filters = _.reject(collection.filters, function (f) {
                    return f.name == filter
                });
            } else {
                collection.filters = _.reject(collection.filters, function (f) {
                    return f == filter
                });
            }
            if (!options.nofetch) {
                collection.fetch({reset: true});
            }
        },

        /**
         * Augment Fetch with all information
         */
        fetch: function (options) {
            var collection = this;

            options = options ? _.clone(options) : {};
            options.data = options.data ? options.data : {};
            options.data["q"] = JSON.stringify({"filters": collection.filters});

            return Tornado.Collection.prototype.fetch.call(collection, options);
        }

    });

    return Tornado;
}).call(window);
<|endoftext|>


<commit_before>/*<![CDATA[*/
    var perPage=7;
    var numPages=6;
    var firstText ='First';
    var lastText ='Last';
    var prevText ='« Previous';
    var nextText ='Next »';
    var urlactivepage=location.href;
    var home_page="/";
  /*]]>*/

  /*<![CDATA[*/
    if (typeof firstText == "undefined") firstText = "First";
    if (typeof lastText == "undefined") lastText = "Last";
    var noPage;
    var currentPage;
    var currentPageNo;
    var postLabel;
    pagecurrentg();

    function looppagecurrentg(pageInfo) {
        var html = '';
        pageNumber = parseInt(numPages / 2);
        if (pageNumber == numPages - pageNumber) {
            numPages = pageNumber * 2 + 1
        }
        pageStart = currentPageNo - pageNumber;
        if (pageStart < 1) pageStart = 1;
        lastPageNo = parseInt(pageInfo / perPage) + 1;
        if (lastPageNo - 1 == pageInfo / perPage) lastPageNo = lastPageNo - 1;
        pageEnd = pageStart + numPages - 1;
        if (pageEnd > lastPageNo) pageEnd = lastPageNo;
        html += "Page " + currentPageNo + ' of ' + lastPageNo + "";
        var prevNumber = parseInt(currentPageNo) - 1;

		//Iccsi was here, doing magic
        if (currentPageNo > 1) {
			if (currentPage == "page") {
			  html += '' + firstText + ''
			} else {
			  html += '' + firstText + ''
			}
		}

		if (currentPageNo > 2) {
            if (currentPageNo == 3) {
                if (currentPage == "page") {
                    html += '' + prevText + ''
                } else {
                    html += '' + prevText + ''
                }
            } else {
                if (currentPage == "page") {
                    html += '' + prevText + ''
                } else {
                    html += '' + prevText + ''
                }
            }
        }
        if (pageStart > 1) {
            if (currentPage == "page") {
                html += '1'
            } else {
                html += '1'
            }
        }
        if (pageStart > 2) {
            html += ' ... '
        }
        for (var jj = pageStart; jj <= pageEnd; jj++) {
            if (currentPageNo == jj) {
                html += '' + jj + ''
            } else if (jj == 1) {
                if (currentPage == "page") {
                    html += '1'
                } else {
                    html += '1'
                }
            } else {
                if (currentPage == "page") {
                    html += '' + jj + ''
                } else {
                    html += '' + jj + ''
                }
            }
        }
        if (pageEnd < lastPageNo - 1) {
            html += '...'
        }
        if (pageEnd < lastPageNo) {
            if (currentPage == "page") {
                html += '' + lastPageNo + ''
            } else {
                html += '' + lastPageNo + ''
            }
        }

        var nextnumber = parseInt(currentPageNo) + 1;
        if (currentPageNo < (lastPageNo - 1)) {
            if (currentPage == "page") {
                html += '' + nextText + ''
            } else {
                html += '' + nextText + ''
            }
		}

		if (currentPageNo < lastPageNo) {
			//Iccsi was here, doing magic
			if (currentPage == "page") {
			  html += '' + lastText + ''
			} else {
			  html += '' + lastText + ''
			}
        }

        var pageArea = document.getElementsByName("pageArea");
        var blogPager = document.getElementById("blog-pager");
        for (var p = 0; p < pageArea.length; p++) {
            pageArea[p].innerHTML = html
        }
        if (pageArea && pageArea.length > 0) {
            html = ''
        }
        if (blogPager) {
            blogPager.innerHTML = html
        }
    }

    function totalcountdata(root) {
        var feed = root.feed;
        var totaldata = parseInt(feed.openSearch$totalResults.$t, 10);
        console.log(totaldata);
        looppagecurrentg(totaldata)
    }

    function pagecurrentg() {
        var thisUrl = urlactivepage;
        if (thisUrl.indexOf("/search/label/") != -1) {
            if (thisUrl.indexOf("?updated-max") != -1) {
                postLabel = thisUrl.substring(thisUrl.indexOf("/search/label/") + 14, thisUrl.indexOf("?updated-max"))
            } else {
                postLabel = thisUrl.substring(thisUrl.indexOf("/search/label/") + 14, thisUrl.indexOf("?&max"))
            }
        }
        if (thisUrl.indexOf(".html") == -1) {
            if (thisUrl.indexOf("/search/label/") == -1) {
                currentPage = "page";
                if (urlactivepage.indexOf("#PageNo=") != -1) {
                    currentPageNo = urlactivepage.substring(urlactivepage.indexOf("#PageNo=") + 8, urlactivepage.length)
                } else {
                    currentPageNo = 1
                }
                if(thisUrl.indexOf("q=") == -1){
                	document.write("


<commit_before>/* Copyright 2014 Open Ag Data Alliance
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

'use strict';

var request = require('superagent');
// TODO: URIjs is big, find smaller alternative
var URI = require('URIjs');
var objectAssign = require('object-assign');
var jwt = require('jsonwebtoken');
var jws = require('jws');
var pem = require('rsa-pem-from-mod-exp');
var crypto = require('crypto');

var core = {};

var options = {};
var stuff = {};

core.init = function(opts) {
    objectAssign(options, opts);
};

function storeState(stateObj, callback) {
    // Make sure neither or both state storing functions are overridden
    if (core.retrieveState != retrieveState) {
        callback('Overrode retrieveState but not storeState!');
    }

    // Cryptographically secure random bytes
    var stateTok = crypto.randomBytes(16);

    // Make it base64URL
    stateTok = stateTok.toString('base64')
        .replace(/\+/g, '-')
        .replace(/\//g, '_')
        .replace(/=/g, '');

    // Rembmer stuff
    stuff[stateTok] = stateObj;

    return callback(null, stateTok);
}

function retrieveState(stateTok, callback) {
    // Make sure neither or both state storing functions are overridden
    if (core.storeState != storeState) {
        callback('Overrode storeState but not retrieveState!');
    }

    // Retrie stored state
    var stateObj = stuff[stateTok];

    // Only use each state once
    delete stuff[stateTok];

    return callback(null, stateObj);
}

// These can be replaced with to change how state is stored
// TODO: Should these be exposed somehow for browser and/or middleware?
core.storeState = storeState;
core.retrieveState = retrieveState;

function authorize(domain, configuration, parameters, redirect, callback) {
    var params = objectAssign({}, options, parameters);
    var key = params.privateKey;

    delete params['client_secret'];
    delete params.privateKey;

    // TODO: HTTPS
    var req = request.get('http://' + domain + '/.well-known/' + configuration);
    if (req.buffer) { req.buffer(); }
    req.end(function(err, resp) {
        if (err) { return redirect(err); }

        try {
            var conf = JSON.parse(resp.text);
            // Stuff to remember for when redirect is received
            var stateObj = {
                key: key,
                domain: domain,
                conf: conf,
                callback: callback,
                options: params,
            };

            core.storeState(stateObj, function(err, stateTok) {
                // Construct authorization redirect
                var uri = new URI(conf['authorization_endpoint']);
                uri.addQuery({state: stateTok}).addQuery(params);

                // Redirect the user to constructed uri
                return redirect(err, uri && uri.toString());
            });
        } catch (err) {
            // Should I be passing the error to both?
            return combineCallbacks(redirect, callback)(err);
        }
    });
}

core.getIDToken = function getIDToken(domain, opts, redirect, cb) {
    var configuration = 'openid-configuration';
    var params = objectAssign({}, opts,
            {
                // TODO: Merge scopes instead of overwriting them???
                scope: 'openid profile',
            });

    authorize(domain, configuration, params, redirect, cb);
};

core.getAccessToken = function getAccessToken(domain, opts, redirect, cb) {
    var configuration = 'oada-configuration';

    authorize(domain, configuration, opts, redirect, cb);
};

function combineCallbacks() {
    var callbacks = arguments;

    return function callback(err, result) {
        for (var i = 0; i < callbacks.length; i++) {
            if (typeof callbacks[i] === 'function') {
                callbacks[i](err, result);
            }
        }
    };
}

// TODO: Check issuer
function verifyIDToken(state, parameters, callback) {
    if (!parameters || !parameters['id_token']) {
        return callback(null, parameters);
    }

    var decodedToken = jws.decode(parameters['id_token']);

    var req = request.get(state.conf['jwks_uri']);
    if (req.buffer) { req.buffer(); }
    req.end(function(err, resp) {
        if (err) { return callback(err); }

        var jwks = JSON.parse(resp.text);
        var jwk;

        console.log('token'); console.dir(decodedToken);
        console.log('jwks'); console.dir(jwks);

        for (var i = 0; i < jwks.keys.length; i++) {
            if (jwks.keys[i].kid === decodedToken.header.kid) {
                jwk = jwks.keys[i];
                break;
            }
        }

        var pemKey = pem(jwk.n, jwk.e);

        jwt.verify(parameters['id_token'], pemKey, function(err, token) {
            parameters['id_token'] = token;

            callback(err, parameters);
        });
    });
}

function generateClientSecret(key, issuer, audience, accessCode) {
    var sec = {
        ac: accessCode,
    };
    var options = {
        algorithm: 'RS256',
        audience: audience,
        issuer: issuer,
        headers: {
            kid: key.kid,
        },
    };

    return jwt.sign(sec, key.pem, options);
}

function exchangeCode(state, parameters, callback) {
    if (!parameters['code']) {
        return verifyIDToken(state, parameters, callback);
    }

    var params = {
        'grant_type': 'authorization_code',
        'redirect_uri': state.options['redirect_uri'],
        'client_secret': generateClientSecret(
                state.key,
                state.options['client_id'],
                state.conf['token_endpoint'],
                parameters.code),
        'client_id': state.options['client_id'],
        'code': parameters.code,
    };

    console.log(params);

    request.post(state.conf['token_endpoint'])
        .type('form')
        .send(params)
        .end(function(err, resp) {
            if (err) { return callback(err); }

            if (!resp.ok) { return callback('Token request failed'); }

            var token;
            try {
                token = JSON.parse(resp.text);
            } catch (err) {
                return callback(err);
            }

            verifyIDToken(state, token, callback);
        });
}

// TODO: Should I be able to register callbacks in two places?
core.handleRedirect = function handleRedirect(parameters, callback) {
    var stateTok = parameters.state;

    core.retrieveState(stateTok, function(err, stateObj) {
        var cb = combineCallbacks(stateObj && stateObj.callback, callback);

        if (stateObj) {
            exchangeCode(stateObj, parameters, cb);
        } else {
            cb('Spurrious redirect received', parameters);
        }
    });
};

module.exports = core;
<commit_msg>Handle GET errors better<commit_after>/* Copyright 2014 Open Ag Data Alliance
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

'use strict';

var request = require('superagent');
// TODO: URIjs is big, find smaller alternative
var URI = require('URIjs');
var objectAssign = require('object-assign');
var jwt = require('jsonwebtoken');
var jws = require('jws');
var pem = require('rsa-pem-from-mod-exp');
var crypto = require('crypto');

var core = {};

var options = {};
var stuff = {};

core.init = function(opts) {
    objectAssign(options, opts);
};

function storeState(stateObj, callback) {
    // Make sure neither or both state storing functions are overridden
    if (core.retrieveState != retrieveState) {
        callback('Overrode retrieveState but not storeState!');
    }

    // Cryptographically secure random bytes
    var stateTok = crypto.randomBytes(16);

    // Make it base64URL
    stateTok = stateTok.toString('base64')
        .replace(/\+/g, '-')
        .replace(/\//g, '_')
        .replace(/=/g, '');

    // Rembmer stuff
    stuff[stateTok] = stateObj;

    return callback(null, stateTok);
}

function retrieveState(stateTok, callback) {
    // Make sure neither or both state storing functions are overridden
    if (core.storeState != storeState) {
        callback('Overrode storeState but not retrieveState!');
    }

    // Retrie stored state
    var stateObj = stuff[stateTok];

    // Only use each state once
    delete stuff[stateTok];

    return callback(null, stateObj);
}

// These can be replaced with to change how state is stored
// TODO: Should these be exposed somehow for browser and/or middleware?
core.storeState = storeState;
core.retrieveState = retrieveState;

function authorize(domain, configuration, parameters, redirect, callback) {
    var params = objectAssign({}, options, parameters);
    var key = params.privateKey;

    delete params['client_secret'];
    delete params.privateKey;

    // Should I be passing the error to both?
    var errCallback = combineCallbacks(redirect, callback);

    // TODO: HTTPS
    var req = request.get('http://' + domain + '/.well-known/' + configuration);
    if (req.buffer) { req.buffer(); }
    req.end(function(resp) {
        if (resp.error) { return errCallback(resp.error); }

        try {
            var conf = JSON.parse(resp.text);
            // Stuff to remember for when redirect is received
            var stateObj = {
                key: key,
                domain: domain,
                conf: conf,
                callback: callback,
                options: params,
            };

            core.storeState(stateObj, function(err, stateTok) {
                // Construct authorization redirect
                var uri = new URI(conf['authorization_endpoint']);
                uri.addQuery({state: stateTok}).addQuery(params);

                // Redirect the user to constructed uri
                return redirect(err, uri && uri.toString());
            });
        } catch (err) {
            return errCallback(err);
        }
    });
}

core.getIDToken = function getIDToken(domain, opts, redirect, cb) {
    var configuration = 'openid-configuration';
    var params = objectAssign({}, opts,
            {
                // TODO: Merge scopes instead of overwriting them???
                scope: 'openid profile',
            });

    authorize(domain, configuration, params, redirect, cb);
};

core.getAccessToken = function getAccessToken(domain, opts, redirect, cb) {
    var configuration = 'oada-configuration';

    authorize(domain, configuration, opts, redirect, cb);
};

function combineCallbacks() {
    var callbacks = arguments;

    return function callback(err, result) {
        for (var i = 0; i < callbacks.length; i++) {
            if (typeof callbacks[i] === 'function') {
                callbacks[i](err, result);
            }
        }
    };
}

// TODO: Check issuer
function verifyIDToken(state, parameters, callback) {
    if (!parameters || !parameters['id_token']) {
        return callback(null, parameters);
    }

    var decodedToken = jws.decode(parameters['id_token']);

    var req = request.get(state.conf['jwks_uri']);
    if (req.buffer) { req.buffer(); }
    req.end(function(resp) {
        if (resp.error) { return callback(resp.error); }

        var jwks = JSON.parse(resp.text);
        var jwk;

        console.log('token'); console.dir(decodedToken);
        console.log('jwks'); console.dir(jwks);

        for (var i = 0; i < jwks.keys.length; i++) {
            if (jwks.keys[i].kid === decodedToken.header.kid) {
                jwk = jwks.keys[i];
                break;
            }
        }

        var pemKey = pem(jwk.n, jwk.e);

        jwt.verify(parameters['id_token'], pemKey, function(err, token) {
            parameters['id_token'] = token;

            callback(err, parameters);
        });
    });
}

function generateClientSecret(key, issuer, audience, accessCode) {
    var sec = {
        ac: accessCode,
    };
    var options = {
        algorithm: 'RS256',
        audience: audience,
        issuer: issuer,
        headers: {
            kid: key.kid,
        },
    };

    return jwt.sign(sec, key.pem, options);
}

function exchangeCode(state, parameters, callback) {
    if (!parameters['code']) {
        return verifyIDToken(state, parameters, callback);
    }

    var params = {
        'grant_type': 'authorization_code',
        'redirect_uri': state.options['redirect_uri'],
        'client_secret': generateClientSecret(
                state.key,
                state.options['client_id'],
                state.conf['token_endpoint'],
                parameters.code),
        'client_id': state.options['client_id'],
        'code': parameters.code,
    };

    console.log(params);

    request.post(state.conf['token_endpoint'])
        .type('form')
        .send(params)
        .end(function(err, resp) {
            if (err) { return callback(err); }

            if (!resp.ok) { return callback('Token request failed'); }

            var token;
            try {
                token = JSON.parse(resp.text);
            } catch (err) {
                return callback(err);
            }

            verifyIDToken(state, token, callback);
        });
}

// TODO: Should I be able to register callbacks in two places?
core.handleRedirect = function handleRedirect(parameters, callback) {
    var stateTok = parameters.state;

    core.retrieveState(stateTok, function(err, stateObj) {
        var cb = combineCallbacks(stateObj && stateObj.callback, callback);

        if (stateObj) {
            exchangeCode(stateObj, parameters, cb);
        } else {
            cb('Spurrious redirect received', parameters);
        }
    });
};

module.exports = core;
<|endoftext|>