code:
/* Zepto v1.1.3 - zepto event ajax form ie - zeptojs.com/license */

var Zepto = (function() {
  var undefined, key, $, classList, emptyArray = [], slice = emptyArray.slice, filter = emptyArray.filter,
    document = window.document,
    elementDisplay = {}, classCache = {},
    cssNumber = { 'column-count': 1, 'columns': 1, 'font-weight': 1, 'line-height': 1,'opacity': 1, 'z-index': 1, 'zoom': 1 },
    fragmentRE = /^\s*<(\w+|!)[^>]*>/,
    singleTagRE = /^<(\w+)\s*\/?>(?:<\/\1>|)$/,
    tagExpanderRE = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,
    rootNodeRE = /^(?:body|html)$/i,
    capitalRE = /([A-Z])/g,

    // special attributes that should be get/set via method calls
    methodAttributes = ['val', 'css', 'html', 'text', 'data', 'width', 'height', 'offset'],

    adjacencyOperators = [ 'after', 'prepend', 'before', 'append' ],
    table = document.createElement('table'),
    tableRow = document.createElement('tr'),
    containers = {
      'tr': document.createElement('tbody'),
      'tbody': table, 'thead': table, 'tfoot': table,
      'td': tableRow, 'th': tableRow,
      '*': document.createElement('div')
    },
    readyRE = /complete|loaded|interactive/,
    simpleSelectorRE = /^[\w-]*$/,
    class2type = {},
    toString = class2type.toString,
    zepto = {},
    camelize, uniq,
    tempParent = document.createElement('div'),
    propMap = {
      'tabindex': 'tabIndex',
      'readonly': 'readOnly',
      'for': 'htmlFor',
      'class': 'className',
      'maxlength': 'maxLength',
      'cellspacing': 'cellSpacing',
      'cellpadding': 'cellPadding',
      'rowspan': 'rowSpan',
      'colspan': 'colSpan',
      'usemap': 'useMap',
      'frameborder': 'frameBorder',
      'contenteditable': 'contentEditable'
    },
    isArray = Array.isArray ||
      function(object){ return object instanceof Array }

  zepto.matches = function(element, selector) {
    if (!selector || !element || element.nodeType !== 1) return false
    var matchesSelector = element.webkitMatchesSelector || element.mozMatchesSelector ||
                          element.oMatchesSelector || element.matchesSelector
    if (matchesSelector) return matchesSelector.call(element, selector)
    // fall back to performing a selector:
    var match, parent = element.parentNode, temp = !parent
    if (temp) (parent = tempParent).appendChild(element)
    match = ~zepto.qsa(parent, selector).indexOf(element)
    temp && tempParent.removeChild(element)
    return match
  }

  function type(obj) {
    return obj == null ? String(obj) :
      class2type[toString.call(obj)] || "object"
  }

  function isFunction(value) { return type(value) == "function" }
  function isWindow(obj)     { return obj != null && obj == obj.window }
  function isDocument(obj)   { return obj != null && obj.nodeType == obj.DOCUMENT_NODE }
  function isObject(obj)     { return type(obj) == "object" }
  function isPlainObject(obj) {
    return isObject(obj) && !isWindow(obj) && Object.getPrototypeOf(obj) == Object.prototype
  }
  function likeArray(obj) { return typeof obj.length == 'number' }

  function compact(array) { return filter.call(array, function(item){ return item != null }) }
  function flatten(array) { return array.length > 0 ? $.fn.concat.apply([], array) : array }
  camelize = function(str){ return str.replace(/-+(.)?/g, function(match, chr){ return chr ? chr.toUpperCase() : '' }) }
  function dasherize(str) {
    return str.replace(/::/g, '/')
           .replace(/([A-Z]+)([A-Z][a-z])/g, '$1_$2')
           .replace(/([a-z\d])([A-Z])/g, '$1_$2')
           .replace(/_/g, '-')
           .toLowerCase()
  }
  uniq = function(array){ return filter.call(array, function(item, idx){ return array.indexOf(item) == idx }) }

  function classRE(name) {
    return name in classCache ?
      classCache[name] : (classCache[name] = new RegExp('(^|\\s)' + name + '(\\s|$)'))
  }

  function maybeAddPx(name, value) {
    return (typeof value == "number" && !cssNumber[dasherize(name)]) ? value + "px" : value
  }

  function defaultDisplay(nodeName) {
    var element, display
    if (!elementDisplay[nodeName]) {
      element = document.createElement(nodeName)
      document.body.appendChild(element)
      display = getComputedStyle(element, '').getPropertyValue("display")
      element.parentNode.removeChild(element)
      display == "none" && (display = "block")
      elementDisplay[nodeName] = display
    }
    return elementDisplay[nodeName]
  }

  function children(element) {
    return 'children' in element ?
      slice.call(element.children) :
      $.map(element.childNodes, function(node){ if (node.nodeType == 1) return node })
  }

  // `$.zepto.fragment` takes a html string and an optional tag name
  // to generate DOM nodes nodes from the given html string.
  // The generated DOM nodes are returned as an array.
  // This function can be overriden in plugins for example to make
  // it compatible with browsers that don't support the DOM fully.
  zepto.fragment = function(html, name, properties) {
    var dom, nodes, container

    // A special case optimization for a single tag
    if (singleTagRE.test(html)) dom = $(document.createElement(RegExp.$1))

    if (!dom) {
      if (html.replace) html = html.replace(tagExpanderRE, "<$1></$2>")
      if (name === undefined) name = fragmentRE.test(html) && RegExp.$1
      if (!(name in containers)) name = '*'

      container = containers[name]
      container.innerHTML = '' + html
      dom = $.each(slice.call(container.childNodes), function(){
        container.removeChild(this)
      })
    }

    if (isPlainObject(properties)) {
      nodes = $(dom)
      $.each(properties, function(key, value) {
        if (methodAttributes.indexOf(key) > -1) nodes[key](value)
        else nodes.attr(key, value)
      })
    }

    return dom
  }

  // `$.zepto.Z` swaps out the prototype of the given `dom` array
  // of nodes with `$.fn` and thus supplying all the Zepto functions
  // to the array. Note that `__proto__` is not supported on Internet
  // Explorer. This method can be overriden in plugins.
  zepto.Z = function(dom, selector) {
    dom = dom || []
    dom.__proto__ = $.fn
    dom.selector = selector || ''
    return dom
  }

  // `$.zepto.isZ` should return `true` if the given object is a Zepto
  // collection. This method can be overriden in plugins.
  zepto.isZ = function(object) {
    return object instanceof zepto.Z
  }

  // `$.zepto.init` is Zepto's counterpart to jQuery's `$.fn.init` and
  // takes a CSS selector and an optional context (and handles various
  // special cases).
  // This method can be overriden in plugins.
  zepto.init = function(selector, context) {
    var dom
    // If nothing given, return an empty Zepto collection
    if (!selector) return zepto.Z()
    // Optimize for string selectors
    else if (typeof selector == 'string') {
      selector = selector.trim()
      // If it's a html fragment, create nodes from it
      // Note: In both Chrome 21 and Firefox 15, DOM error 12
      // is thrown if the fragment doesn't begin with <
      if (selector[0] == '<' && fragmentRE.test(selector))
        dom = zepto.fragment(selector, RegExp.$1, context), selector = null
      // If there's a context, create a collection on that context first, and select
      // nodes from there
      else if (context !== undefined) return $(context).find(selector)
      // If it's a CSS selector, use it to select nodes.
      else dom = zepto.qsa(document, selector)
    }
    // If a function is given, call it when the DOM is ready
    else if (isFunction(selector)) return $(document).ready(selector)
    // If a Zepto collection is given, just return it
    else if (zepto.isZ(selector)) return selector
    else {
      // normalize array if an array of nodes is given
      if (isArray(selector)) dom = compact(selector)
      // Wrap DOM nodes.
      else if (isObject(selector))
        dom = [selector], selector = null
      // If it's a html fragment, create nodes from it
      else if (fragmentRE.test(selector))
        dom = zepto.fragment(selector.trim(), RegExp.$1, context), selector = null
      // If there's a context, create a collection on that context first, and select
      // nodes from there
      else if (context !== undefined) return $(context).find(selector)
      // And last but no least, if it's a CSS selector, use it to select nodes.
      else dom = zepto.qsa(document, selector)
    }
    // create a new Zepto collection from the nodes found
    return zepto.Z(dom, selector)
  }

  // `$` will be the base `Zepto` object. When calling this
  // function just call `$.zepto.init, which makes the implementation
  // details of selecting nodes and creating Zepto collections
  // patchable in plugins.
  $ = function(selector, context){
    return zepto.init(selector, context)
  }

  function extend(target, source, deep) {
    for (key in source)
      if (deep && (isPlainObject(source[key]) || isArray(source[key]))) {
        if (isPlainObject(source[key]) && !isPlainObject(target[key]))
          target[key] = {}
        if (isArray(source[key]) && !isArray(target[key]))
          target[key] = []
        extend(target[key], source[key], deep)
      }
      else if (source[key] !== undefined) target[key] = source[key]
  }

  // Copy all but undefined properties from one or more
  // objects to the `target` object.
  $.extend = function(target){
    var deep, args = slice.call(arguments, 1)
    if (typeof target == 'boolean') {
      deep = target
      target = args.shift()
    }
    args.forEach(function(arg){ extend(target, arg, deep) })
    return target
  }

  // `$.zepto.qsa` is Zepto's CSS selector implementation which
  // uses `document.querySelectorAll` and optimizes for some special cases, like `#id`.
  // This method can be overriden in plugins.
  zepto.qsa = function(element, selector){
    var found,
        maybeID = selector[0] == '#',
        maybeClass = !maybeID && selector[0] == '.',
        nameOnly = maybeID || maybeClass ? selector.slice(1) : selector, // Ensure that a 1 char tag name still gets checked
        isSimple = simpleSelectorRE.test(nameOnly)
    return (isDocument(element) && isSimple && maybeID) ?
      ( (found = element.getElementById(nameOnly)) ? [found] : [] ) :
      (element.nodeType !== 1 && element.nodeType !== 9) ? [] :
      slice.call(
        isSimple && !maybeID ?
          maybeClass ? element.getElementsByClassName(nameOnly) : // If it's simple, it could be a class
          element.getElementsByTagName(selector) : // Or a tag
          element.querySelectorAll(selector) // Or it's not simple, and we need to query all
      )
  }

  function filtered(nodes, selector) {
    return selector == null ? $(nodes) : $(nodes).filter(selector)
  }

  $.contains = function(parent, node) {
    return parent !== node && parent.contains(node)
  }

  function funcArg(context, arg, idx, payload) {
    return isFunction(arg) ? arg.call(context, idx, payload) : arg
  }

  function setAttribute(node, name, value) {
    value == null ? node.removeAttribute(name) : node.setAttribute(name, value)
  }

  // access className property while respecting SVGAnimatedString
  function className(node, value){
    var klass = node.className,
        svg   = klass && klass.baseVal !== undefined

    if (value === undefined) return svg ? klass.baseVal : klass
    svg ? (klass.baseVal = value) : (node.className = value)
  }

  // "true"  => true
  // "false" => false
  // "null"  => null
  // "42"    => 42
  // "42.5"  => 42.5
  // "08"    => "08"
  // JSON    => parse if valid
  // String  => self
  function deserializeValue(value) {
    var num
    try {
      return value ?
        value == "true" ||
        ( value == "false" ? false :
          value == "null" ? null :
          !/^0/.test(value) && !isNaN(num = Number(value)) ? num :
          /^[\[\{]/.test(value) ? $.parseJSON(value) :
          value )
        : value
    } catch(e) {
      return value
    }
  }

  $.type = type
  $.isFunction = isFunction
  $.isWindow = isWindow
  $.isArray = isArray
  $.isPlainObject = isPlainObject

  $.isEmptyObject = function(obj) {
    var name
    for (name in obj) return false
    return true
  }

  $.inArray = function(elem, array, i){
    return emptyArray.indexOf.call(array, elem, i)
  }

  $.camelCase = camelize
  $.trim = function(str) {
    return str == null ? "" : String.prototype.trim.call(str)
  }

  // plugin compatibility
  $.uuid = 0
  $.support = { }
  $.expr = { }

  $.map = function(elements, callback){
    var value, values = [], i, key
    if (likeArray(elements))
      for (i = 0; i < elements.length; i++) {
        value = callback(elements[i], i)
        if (value != null) values.push(value)
      }
    else
      for (key in elements) {
        value = callback(elements[key], key)
        if (value != null) values.push(value)
      }
    return flatten(values)
  }

  $.each = function(elements, callback){
    var i, key
    if (likeArray(elements)) {
      for (i = 0; i < elements.length; i++)
        if (callback.call(elements[i], i, elements[i]) === false) return elements
    } else {
      for (key in elements)
        if (callback.call(elements[key], key, elements[key]) === false) return elements
    }

    return elements
  }

  $.grep = function(elements, callback){
    return filter.call(elements, callback)
  }

  if (window.JSON) $.parseJSON = JSON.parse

  // Populate the class2type map
  $.each("Boolean Number String Function Array Date RegExp Object Error".split(" "), function(i, name) {
    class2type[ "[object " + name + "]" ] = name.toLowerCase()
  })

  // Define methods that will be available on all
  // Zepto collections
  $.fn = {
    // Because a collection acts like an array
    // copy over these useful array functions.
    forEach: emptyArray.forEach,
    reduce: emptyArray.reduce,
    push: emptyArray.push,
    sort: emptyArray.sort,
    indexOf: emptyArray.indexOf,
    concat: emptyArray.concat,

    // `map` and `slice` in the jQuery API work differently
    // from their array counterparts
    map: function(fn){
      return $($.map(this, function(el, i){ return fn.call(el, i, el) }))
    },
    slice: function(){
      return $(slice.apply(this, arguments))
    },

    ready: function(callback){
      // need to check if document.body exists for IE as that browser reports
      // document ready when it hasn't yet created the body element
      if (readyRE.test(document.readyState) && document.body) callback($)
      else document.addEventListener('DOMContentLoaded', function(){ callback($) }, false)
      return this
    },
    get: function(idx){
      return idx === undefined ? slice.call(this) : this[idx >= 0 ? idx : idx + this.length]
    },
    toArray: function(){ return this.get() },
    size: function(){
      return this.length
    },
    remove: function(){
      return this.each(function(){
        if (this.parentNode != null)
          this.parentNode.removeChild(this)
      })
    },
    each: function(callback){
      emptyArray.every.call(this, function(el, idx){
        return callback.call(el, idx, el) !== false
      })
      return this
    },
    filter: function(selector){
      if (isFunction(selector)) return this.not(this.not(selector))
      return $(filter.call(this, function(element){
        return zepto.matches(element, selector)
      }))
    },
    add: function(selector,context){
      return $(uniq(this.concat($(selector,context))))
    },
    is: function(selector){
      return this.length > 0 && zepto.matches(this[0], selector)
    },
    not: function(selector){
      var nodes=[]
      if (isFunction(selector) && selector.call !== undefined)
        this.each(function(idx){
          if (!selector.call(this,idx)) nodes.push(this)
        })
      else {
        var excludes = typeof selector == 'string' ? this.filter(selector) :
          (likeArray(selector) && isFunction(selector.item)) ? slice.call(selector) : $(selector)
        this.forEach(function(el){
          if (excludes.indexOf(el) < 0) nodes.push(el)
        })
      }
      return $(nodes)
    },
    has: function(selector){
      return this.filter(function(){
        return isObject(selector) ?
          $.contains(this, selector) :
          $(this).find(selector).size()
      })
    },
    eq: function(idx){
      return idx === -1 ? this.slice(idx) : this.slice(idx, + idx + 1)
    },
    first: function(){
      var el = this[0]
      return el && !isObject(el) ? el : $(el)
    },
    last: function(){
      var el = this[this.length - 1]
      return el && !isObject(el) ? el : $(el)
    },
    find: function(selector){
      var result, $this = this
      if (typeof selector == 'object')
        result = $(selector).filter(function(){
          var node = this
          return emptyArray.some.call($this, function(parent){
            return $.contains(parent, node)
          })
        })
      else if (this.length == 1) result = $(zepto.qsa(this[0], selector))
      else result = this.map(function(){ return zepto.qsa(this, selector) })
      return result
    },
    closest: function(selector, context){
      var node = this[0], collection = false
      if (typeof selector == 'object') collection = $(selector)
      while (node && !(collection ? collection.indexOf(node) >= 0 : zepto.matches(node, selector)))
        node = node !== context && !isDocument(node) && node.parentNode
      return $(node)
    },
    parents: function(selector){
      var ancestors = [], nodes = this
      while (nodes.length > 0)
        nodes = $.map(nodes, function(node){
          if ((node = node.parentNode) && !isDocument(node) && ancestors.indexOf(node) < 0) {
            ancestors.push(node)
            return node
          }
        })
      return filtered(ancestors, selector)
    },
    parent: function(selector){
      return filtered(uniq(this.pluck('parentNode')), selector)
    },
    children: function(selector){
      return filtered(this.map(function(){ return children(this) }), selector)
    },
    contents: function() {
      return this.map(function() { return slice.call(this.childNodes) })
    },
    siblings: function(selector){
      return filtered(this.map(function(i, el){
        return filter.call(children(el.parentNode), function(child){ return child!==el })
      }), selector)
    },
    empty: function(){
      return this.each(function(){ this.innerHTML = '' })
    },
    // `pluck` is borrowed from Prototype.js
    pluck: function(property){
      return $.map(this, function(el){ return el[property] })
    },
    show: function(){
      return this.each(function(){
        this.style.display == "none" && (this.style.display = '')
        if (getComputedStyle(this, '').getPropertyValue("display") == "none")
          this.style.display = defaultDisplay(this.nodeName)
      })
    },
    replaceWith: function(newContent){
      return this.before(newContent).remove()
    },
    wrap: function(structure){
      var func = isFunction(structure)
      if (this[0] && !func)
        var dom   = $(structure).get(0),
            clone = dom.parentNode || this.length > 1

      return this.each(function(index){
        $(this).wrapAll(
          func ? structure.call(this, index) :
            clone ? dom.cloneNode(true) : dom
        )
      })
    },
    wrapAll: function(structure){
      if (this[0]) {
        $(this[0]).before(structure = $(structure))
        var children
        // drill down to the inmost element
        while ((children = structure.children()).length) structure = children.first()
        $(structure).append(this)
      }
      return this
    },
    wrapInner: function(structure){
      var func = isFunction(structure)
      return this.each(function(index){
        var self = $(this), contents = self.contents(),
            dom  = func ? structure.call(this, index) : structure
        contents.length ? contents.wrapAll(dom) : self.append(dom)
      })
    },
    unwrap: function(){
      this.parent().each(function(){
        $(this).replaceWith($(this).children())
      })
      return this
    },
    clone: function(){
      return this.map(function(){ return this.cloneNode(true) })
    },
    hide: function(){
      return this.css("display", "none")
    },
    toggle: function(setting){
      return this.each(function(){
        var el = $(this)
        ;(setting === undefined ? el.css("display") == "none" : setting) ? el.show() : el.hide()
      })
    },
    prev: function(selector){ return $(this.pluck('previousElementSibling')).filter(selector || '*') },
    next: function(selector){ return $(this.pluck('nextElementSibling')).filter(selector || '*') },
    html: function(html){
      return arguments.length === 0 ?
        (this.length > 0 ? this[0].innerHTML : null) :
        this.each(function(idx){
          var originHtml = this.innerHTML
          $(this).empty().append( funcArg(this, html, idx, originHtml) )
        })
    },
    text: function(text){
      return arguments.length === 0 ?
        (this.length > 0 ? this[0].textContent : null) :
        this.each(function(){ this.textContent = (text === undefined) ? '' : ''+text })
    },
    attr: function(name, value){
      var result
      return (typeof name == 'string' && value === undefined) ?
        (this.length == 0 || this[0].nodeType !== 1 ? undefined :
          (name == 'value' && this[0].nodeName == 'INPUT') ? this.val() :
          (!(result = this[0].getAttribute(name)) && name in this[0]) ? this[0][name] : result
        ) :
        this.each(function(idx){
          if (this.nodeType !== 1) return
          if (isObject(name)) for (key in name) setAttribute(this, key, name[key])
          else setAttribute(this, name, funcArg(this, value, idx, this.getAttribute(name)))
        })
    },
    removeAttr: function(name){
      return this.each(function(){ this.nodeType === 1 && setAttribute(this, name) })
    },
    prop: function(name, value){
      name = propMap[name] || name
      return (value === undefined) ?
        (this[0] && this[0][name]) :
        this.each(function(idx){
          this[name] = funcArg(this, value, idx, this[name])
        })
    },
    data: function(name, value){
      var data = this.attr('data-' + name.replace(capitalRE, '-$1').toLowerCase(), value)
      return data !== null ? deserializeValue(data) : undefined
    },
    val: function(value){
      return arguments.length === 0 ?
        (this[0] && (this[0].multiple ?
           $(this[0]).find('option').filter(function(){ return this.selected }).pluck('value') :
           this[0].value)
        ) :
        this.each(function(idx){
          this.value = funcArg(this, value, idx, this.value)
        })
    },
    offset: function(coordinates){
      if (coordinates) return this.each(function(index){
        var $this = $(this),
            coords = funcArg(this, coordinates, index, $this.offset()),
            parentOffset = $this.offsetParent().offset(),
            props = {
              top:  coords.top  - parentOffset.top,
              left: coords.left - parentOffset.left
            }

        if ($this.css('position') == 'static') props['position'] = 'relative'
        $this.css(props)
      })
      if (this.length==0) return null
      var obj = this[0].getBoundingClientRect()
      return {
        left: obj.left + window.pageXOffset,
        top: obj.top + window.pageYOffset,
        width: Math.round(obj.width),
        height: Math.round(obj.height)
      }
    },
    css: function(property, value){
      if (arguments.length < 2) {
        var element = this[0], computedStyle = getComputedStyle(element, '')
        if(!element) return
        if (typeof property == 'string')
          return element.style[camelize(property)] || computedStyle.getPropertyValue(property)
        else if (isArray(property)) {
          var props = {}
          $.each(isArray(property) ? property: [property], function(_, prop){
            props[prop] = (element.style[camelize(prop)] || computedStyle.getPropertyValue(prop))
          })
          return props
        }
      }

      var css = ''
      if (type(property) == 'string') {
        if (!value && value !== 0)
          this.each(function(){ this.style.removeProperty(dasherize(property)) })
        else
          css = dasherize(property) + ":" + maybeAddPx(property, value)
      } else {
        for (key in property)
          if (!property[key] && property[key] !== 0)
            this.each(function(){ this.style.removeProperty(dasherize(key)) })
          else
            css += dasherize(key) + ':' + maybeAddPx(key, property[key]) + ';'
      }

      return this.each(function(){ this.style.cssText += ';' + css })
    },
    index: function(element){
      return element ? this.indexOf($(element)[0]) : this.parent().children().indexOf(this[0])
    },
    hasClass: function(name){
      if (!name) return false
      return emptyArray.some.call(this, function(el){
        return this.test(className(el))
      }, classRE(name))
    },
    addClass: function(name){
      if (!name) return this
      return this.each(function(idx){
        classList = []
        var cls = className(this), newName = funcArg(this, name, idx, cls)
        newName.split(/\s+/g).forEach(function(klass){
          if (!$(this).hasClass(klass)) classList.push(klass)
        }, this)
        classList.length && className(this, cls + (cls ? " " : "") + classList.join(" "))
      })
    },
    removeClass: function(name){
      return this.each(function(idx){
        if (name === undefined) return className(this, '')
        classList = className(this)
        funcArg(this, name, idx, classList).split(/\s+/g).forEach(function(klass){
          classList = classList.replace(classRE(klass), " ")
        })
        className(this, classList.trim())
      })
    },
    toggleClass: function(name, when){
      if (!name) return this
      return this.each(function(idx){
        var $this = $(this), names = funcArg(this, name, idx, className(this))
        names.split(/\s+/g).forEach(function(klass){
          (when === undefined ? !$this.hasClass(klass) : when) ?
            $this.addClass(klass) : $this.removeClass(klass)
        })
      })
    },
    scrollTop: function(value){
      if (!this.length) return
      var hasScrollTop = 'scrollTop' in this[0]
      if (value === undefined) return hasScrollTop ? this[0].scrollTop : this[0].pageYOffset
      return this.each(hasScrollTop ?
        function(){ this.scrollTop = value } :
        function(){ this.scrollTo(this.scrollX, value) })
    },
    scrollLeft: function(value){
      if (!this.length) return
      var hasScrollLeft = 'scrollLeft' in this[0]
      if (value === undefined) return hasScrollLeft ? this[0].scrollLeft : this[0].pageXOffset
      return this.each(hasScrollLeft ?
        function(){ this.scrollLeft = value } :
        function(){ this.scrollTo(value, this.scrollY) })
    },
    position: function() {
      if (!this.length) return

      var elem = this[0],
        // Get *real* offsetParent
        offsetParent = this.offsetParent(),
        // Get correct offsets
        offset       = this.offset(),
        parentOffset = rootNodeRE.test(offsetParent[0].nodeName) ? { top: 0, left: 0 } : offsetParent.offset()

      // Subtract element margins
      // note: when an element has margin: auto the offsetLeft and marginLeft
      // are the same in Safari causing offset.left to incorrectly be 0
      offset.top  -= parseFloat( $(elem).css('margin-top') ) || 0
      offset.left -= parseFloat( $(elem).css('margin-left') ) || 0

      // Add offsetParent borders
      parentOffset.top  += parseFloat( $(offsetParent[0]).css('border-top-width') ) || 0
      parentOffset.left += parseFloat( $(offsetParent[0]).css('border-left-width') ) || 0

      // Subtract the two offsets
      return {
        top:  offset.top  - parentOffset.top,
        left: offset.left - parentOffset.left
      }
    },
    offsetParent: function() {
      return this.map(function(){
        var parent = this.offsetParent || document.body
        while (parent && !rootNodeRE.test(parent.nodeName) && $(parent).css("position") == "static")
          parent = parent.offsetParent
        return parent
      })
    }
  }

  // for now
  $.fn.detach = $.fn.remove

  // Generate the `width` and `height` functions
  ;['width', 'height'].forEach(function(dimension){
    var dimensionProperty =
      dimension.replace(/./, function(m){ return m[0].toUpperCase() })

    $.fn[dimension] = function(value){
      var offset, el = this[0]
      if (value === undefined) return isWindow(el) ? el['inner' + dimensionProperty] :
        isDocument(el) ? el.documentElement['scroll' + dimensionProperty] :
        (offset = this.offset()) && offset[dimension]
      else return this.each(function(idx){
        el = $(this)
        el.css(dimension, funcArg(this, value, idx, el[dimension]()))
      })
    }
  })

  function traverseNode(node, fun) {
    fun(node)
    for (var key in node.childNodes) traverseNode(node.childNodes[key], fun)
  }

  // Generate the `after`, `prepend`, `before`, `append`,
  // `insertAfter`, `insertBefore`, `appendTo`, and `prependTo` methods.
  adjacencyOperators.forEach(function(operator, operatorIndex) {
    var inside = operatorIndex % 2 //=> prepend, append

    $.fn[operator] = function(){
      // arguments can be nodes, arrays of nodes, Zepto objects and HTML strings
      var argType, nodes = $.map(arguments, function(arg) {
            argType = type(arg)
            return argType == "object" || argType == "array" || arg == null ?
              arg : zepto.fragment(arg)
          }),
          parent, copyByClone = this.length > 1
      if (nodes.length < 1) return this

      return this.each(function(_, target){
        parent = inside ? target : target.parentNode

        // convert all methods to a "before" operation
        target = operatorIndex == 0 ? target.nextSibling :
                 operatorIndex == 1 ? target.firstChild :
                 operatorIndex == 2 ? target :
                 null

        nodes.forEach(function(node){
          if (copyByClone) node = node.cloneNode(true)
          else if (!parent) return $(node).remove()

          traverseNode(parent.insertBefore(node, target), function(el){
            if (el.nodeName != null && el.nodeName.toUpperCase() === 'SCRIPT' &&
               (!el.type || el.type === 'text/javascript') && !el.src)
              window['eval'].call(window, el.innerHTML)
          })
        })
      })
    }

    // after    => insertAfter
    // prepend  => prependTo
    // before   => insertBefore
    // append   => appendTo
    $.fn[inside ? operator+'To' : 'insert'+(operatorIndex ? 'Before' : 'After')] = function(html){
      $(html)[operator](this)
      return this
    }
  })

  zepto.Z.prototype = $.fn

  // Export internal API functions in the `$.zepto` namespace
  zepto.uniq = uniq
  zepto.deserializeValue = deserializeValue
  $.zepto = zepto

  return $
})()

window.Zepto = Zepto
window.$ === undefined && (window.$ = Zepto)

;(function($){
  var _zid = 1, undefined,
      slice = Array.prototype.slice,
      isFunction = $.isFunction,
      isString = function(obj){ return typeof obj == 'string' },
      handlers = {},
      specialEvents={},
      focusinSupported = 'onfocusin' in window,
      focus = { focus: 'focusin', blur: 'focusout' },
      hover = { mouseenter: 'mouseover', mouseleave: 'mouseout' }

  specialEvents.click = specialEvents.mousedown = specialEvents.mouseup = specialEvents.mousemove = 'MouseEvents'

  function zid(element) {
    return element._zid || (element._zid = _zid++)
  }
  function findHandlers(element, event, fn, selector) {
    event = parse(event)
    if (event.ns) var matcher = matcherFor(event.ns)
    return (handlers[zid(element)] || []).filter(function(handler) {
      return handler
        && (!event.e  || handler.e == event.e)
        && (!event.ns || matcher.test(handler.ns))
        && (!fn       || zid(handler.fn) === zid(fn))
        && (!selector || handler.sel == selector)
    })
  }
  function parse(event) {
    var parts = ('' + event).split('.')
    return {e: parts[0], ns: parts.slice(1).sort().join(' ')}
  }
  function matcherFor(ns) {
    return new RegExp('(?:^| )' + ns.replace(' ', ' .* ?') + '(?: |$)')
  }

  function eventCapture(handler, captureSetting) {
    return handler.del &&
      (!focusinSupported && (handler.e in focus)) ||
      !!captureSetting
  }

  function realEvent(type) {
    return hover[type] || (focusinSupported && focus[type]) || type
  }

  function add(element, events, fn, data, selector, delegator, capture){
    var id = zid(element), set = (handlers[id] || (handlers[id] = []))
    events.split(/\s/).forEach(function(event){
      if (event == 'ready') return $(document).ready(fn)
      var handler   = parse(event)
      handler.fn    = fn
      handler.sel   = selector
      // emulate mouseenter, mouseleave
      if (handler.e in hover) fn = function(e){
        var related = e.relatedTarget
        if (!related || (related !== this && !$.contains(this, related)))
          return handler.fn.apply(this, arguments)
      }
      handler.del   = delegator
      var callback  = delegator || fn
      handler.proxy = function(e){
        e = compatible(e)
        if (e.isImmediatePropagationStopped()) return
        e.data = data
        var result = callback.apply(element, e._args == undefined ? [e] : [e].concat(e._args))
        if (result === false) e.preventDefault(), e.stopPropagation()
        return result
      }
      handler.i = set.length
      set.push(handler)
      if ('addEventListener' in element)
        element.addEventListener(realEvent(handler.e), handler.proxy, eventCapture(handler, capture))
    })
  }
  function remove(element, events, fn, selector, capture){
    var id = zid(element)
    ;(events || '').split(/\s/).forEach(function(event){
      findHandlers(element, event, fn, selector).forEach(function(handler){
        delete handlers[id][handler.i]
      if ('removeEventListener' in element)
        element.removeEventListener(realEvent(handler.e), handler.proxy, eventCapture(handler, capture))
      })
    })
  }

  $.event = { add: add, remove: remove }

  $.proxy = function(fn, context) {
    if (isFunction(fn)) {
      var proxyFn = function(){ return fn.apply(context, arguments) }
      proxyFn._zid = zid(fn)
      return proxyFn
    } else if (isString(context)) {
      return $.proxy(fn[context], fn)
    } else {
      throw new TypeError("expected function")
    }
  }

  $.fn.bind = function(event, data, callback){
    return this.on(event, data, callback)
  }
  $.fn.unbind = function(event, callback){
    return this.off(event, callback)
  }
  $.fn.one = function(event, selector, data, callback){
    return this.on(event, selector, data, callback, 1)
  }

  var returnTrue = function(){return true},
      returnFalse = function(){return false},
      ignoreProperties = /^([A-Z]|returnValue$|layer[XY]$)/,
      eventMethods = {
        preventDefault: 'isDefaultPrevented',
        stopImmediatePropagation: 'isImmediatePropagationStopped',
        stopPropagation: 'isPropagationStopped'
      }

  function compatible(event, source) {
    if (source || !event.isDefaultPrevented) {
      source || (source = event)

      $.each(eventMethods, function(name, predicate) {
        var sourceMethod = source[name]
        event[name] = function(){
          this[predicate] = returnTrue
          return sourceMethod && sourceMethod.apply(source, arguments)
        }
        event[predicate] = returnFalse
      })

      if (source.defaultPrevented !== undefined ? source.defaultPrevented :
          'returnValue' in source ? source.returnValue === false :
          source.getPreventDefault && source.getPreventDefault())
        event.isDefaultPrevented = returnTrue
    }
    return event
  }

  function createProxy(event) {
    var key, proxy = { originalEvent: event }
    for (key in event)
      if (!ignoreProperties.test(key) && event[key] !== undefined) proxy[key] = event[key]

    return compatible(proxy, event)
  }

  $.fn.delegate = function(selector, event, callback){
    return this.on(event, selector, callback)
  }
  $.fn.undelegate = function(selector, event, callback){
    return this.off(event, selector, callback)
  }

  $.fn.live = function(event, callback){
    $(document.body).delegate(this.selector, event, callback)
    return this
  }
  $.fn.die = function(event, callback){
    $(document.body).undelegate(this.selector, event, callback)
    return this
  }

  $.fn.on = function(event, selector, data, callback, one){
    var autoRemove, delegator, $this = this
    if (event && !isString(event)) {
      $.each(event, function(type, fn){
        $this.on(type, selector, data, fn, one)
      })
      return $this
    }

    if (!isString(selector) && !isFunction(callback) && callback !== false)
      callback = data, data = selector, selector = undefined
    if (isFunction(data) || data === false)
      callback = data, data = undefined

    if (callback === false) callback = returnFalse

    return $this.each(function(_, element){
      if (one) autoRemove = function(e){
        remove(element, e.type, callback)
        return callback.apply(this, arguments)
      }

      if (selector) delegator = function(e){
        var evt, match = $(e.target).closest(selector, element).get(0)
        if (match && match !== element) {
          evt = $.extend(createProxy(e), {currentTarget: match, liveFired: element})
          return (autoRemove || callback).apply(match, [evt].concat(slice.call(arguments, 1)))
        }
      }

      add(element, event, callback, data, selector, delegator || autoRemove)
    })
  }
  $.fn.off = function(event, selector, callback){
    var $this = this
    if (event && !isString(event)) {
      $.each(event, function(type, fn){
        $this.off(type, selector, fn)
      })
      return $this
    }

    if (!isString(selector) && !isFunction(callback) && callback !== false)
      callback = selector, selector = undefined

    if (callback === false) callback = returnFalse

    return $this.each(function(){
      remove(this, event, callback, selector)
    })
  }

  $.fn.trigger = function(event, args){
    event = (isString(event) || $.isPlainObject(event)) ? $.Event(event) : compatible(event)
    event._args = args
    return this.each(function(){
      // items in the collection might not be DOM elements
      if('dispatchEvent' in this) this.dispatchEvent(event)
      else $(this).triggerHandler(event, args)
    })
  }

  // triggers event handlers on current element just as if an event occurred,
  // doesn't trigger an actual event, doesn't bubble
  $.fn.triggerHandler = function(event, args){
    var e, result
    this.each(function(i, element){
      e = createProxy(isString(event) ? $.Event(event) : event)
      e._args = args
      e.target = element
      $.each(findHandlers(element, event.type || event), function(i, handler){
        result = handler.proxy(e)
        if (e.isImmediatePropagationStopped()) return false
      })
    })
    return result
  }

  // shortcut methods for `.bind(event, fn)` for each event type
  ;('focusin focusout load resize scroll unload click dblclick '+
  'mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave '+
  'change select keydown keypress keyup error').split(' ').forEach(function(event) {
    $.fn[event] = function(callback) {
      return callback ?
        this.bind(event, callback) :
        this.trigger(event)
    }
  })

  ;['focus', 'blur'].forEach(function(name) {
    $.fn[name] = function(callback) {
      if (callback) this.bind(name, callback)
      else this.each(function(){
        try { this[name]() }
        catch(e) {}
      })
      return this
    }
  })

  $.Event = function(type, props) {
    if (!isString(type)) props = type, type = props.type
    var event = document.createEvent(specialEvents[type] || 'Events'), bubbles = true
    if (props) for (var name in props) (name == 'bubbles') ? (bubbles = !!props[name]) : (event[name] = props[name])
    event.initEvent(type, bubbles, true)
    return compatible(event)
  }

})(Zepto)

;(function($){
  var jsonpID = 0,
      document = window.document,
      key,
      name,
      rscript = /<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,
      scriptTypeRE = /^(?:text|application)\/javascript/i,
      xmlTypeRE = /^(?:text|application)\/xml/i,
      jsonType = 'application/json',
      htmlType = 'text/html',
      blankRE = /^\s*$/

  // trigger a custom event and return false if it was cancelled
  function triggerAndReturn(context, eventName, data) {
    var event = $.Event(eventName)
    $(context).trigger(event, data)
    return !event.isDefaultPrevented()
  }

  // trigger an Ajax "global" event
  function triggerGlobal(settings, context, eventName, data) {
    if (settings.global) return triggerAndReturn(context || document, eventName, data)
  }

  // Number of active Ajax requests
  $.active = 0

  function ajaxStart(settings) {
    if (settings.global && $.active++ === 0) triggerGlobal(settings, null, 'ajaxStart')
  }
  function ajaxStop(settings) {
    if (settings.global && !(--$.active)) triggerGlobal(settings, null, 'ajaxStop')
  }

  // triggers an extra global event "ajaxBeforeSend" that's like "ajaxSend" but cancelable
  function ajaxBeforeSend(xhr, settings) {
    var context = settings.context
    if (settings.beforeSend.call(context, xhr, settings) === false ||
        triggerGlobal(settings, context, 'ajaxBeforeSend', [xhr, settings]) === false)
      return false

    triggerGlobal(settings, context, 'ajaxSend', [xhr, settings])
  }
  function ajaxSuccess(data, xhr, settings, deferred) {
    var context = settings.context, status = 'success'
    settings.success.call(context, data, status, xhr)
    if (deferred) deferred.resolveWith(context, [data, status, xhr])
    triggerGlobal(settings, context, 'ajaxSuccess', [xhr, settings, data])
    ajaxComplete(status, xhr, settings)
  }
  // type: "timeout", "error", "abort", "parsererror"
  function ajaxError(error, type, xhr, settings, deferred) {
    var context = settings.context
    settings.error.call(context, xhr, type, error)
    if (deferred) deferred.rejectWith(context, [xhr, type, error])
    triggerGlobal(settings, context, 'ajaxError', [xhr, settings, error || type])
    ajaxComplete(type, xhr, settings)
  }
  // status: "success", "notmodified", "error", "timeout", "abort", "parsererror"
  function ajaxComplete(status, xhr, settings) {
    var context = settings.context
    settings.complete.call(context, xhr, status)
    triggerGlobal(settings, context, 'ajaxComplete', [xhr, settings])
    ajaxStop(settings)
  }

  // Empty function, used as default callback
  function empty() {}

  $.ajaxJSONP = function(options, deferred){
    if (!('type' in options)) return $.ajax(options)

    var _callbackName = options.jsonpCallback,
      callbackName = ($.isFunction(_callbackName) ?
        _callbackName() : _callbackName) || ('jsonp' + (++jsonpID)),
      script = document.createElement('script'),
      originalCallback = window[callbackName],
      responseData,
      abort = function(errorType) {
        $(script).triggerHandler('error', errorType || 'abort')
      },
      xhr = { abort: abort }, abortTimeout

    if (deferred) deferred.promise(xhr)

    $(script).on('load error', function(e, errorType){
      clearTimeout(abortTimeout)
      $(script).off().remove()

      if (e.type == 'error' || !responseData) {
        ajaxError(null, errorType || 'error', xhr, options, deferred)
      } else {
        ajaxSuccess(responseData[0], xhr, options, deferred)
      }

      window[callbackName] = originalCallback
      if (responseData && $.isFunction(originalCallback))
        originalCallback(responseData[0])

      originalCallback = responseData = undefined
    })

    if (ajaxBeforeSend(xhr, options) === false) {
      abort('abort')
      return xhr
    }

    window[callbackName] = function(){
      responseData = arguments
    }

    script.src = options.url.replace(/\?(.+)=\?/, '?$1=' + callbackName)
    document.head.appendChild(script)

    if (options.timeout > 0) abortTimeout = setTimeout(function(){
      abort('timeout')
    }, options.timeout)

    return xhr
  }

  $.ajaxSettings = {
    // Default type of request
    type: 'GET',
    // Callback that is executed before request
    beforeSend: empty,
    // Callback that is executed if the request succeeds
    success: empty,
    // Callback that is executed the the server drops error
    error: empty,
    // Callback that is executed on request complete (both: error and success)
    complete: empty,
    // The context for the callbacks
    context: null,
    // Whether to trigger "global" Ajax events
    global: true,
    // Transport
    xhr: function () {
      return new window.XMLHttpRequest()
    },
    // MIME types mapping
    // IIS returns Javascript as "application/x-javascript"
    accepts: {
      script: 'text/javascript, application/javascript, application/x-javascript',
      json:   jsonType,
      xml:    'application/xml, text/xml',
      html:   htmlType,
      text:   'text/plain'
    },
    // Whether the request is to another domain
    crossDomain: false,
    // Default timeout
    timeout: 0,
    // Whether data should be serialized to string
    processData: true,
    // Whether the browser should be allowed to cache GET responses
    cache: true
  }

  function mimeToDataType(mime) {
    if (mime) mime = mime.split(';', 2)[0]
    return mime && ( mime == htmlType ? 'html' :
      mime == jsonType ? 'json' :
      scriptTypeRE.test(mime) ? 'script' :
      xmlTypeRE.test(mime) && 'xml' ) || 'text'
  }

  function appendQuery(url, query) {
    if (query == '') return url
    return (url + '&' + query).replace(/[&?]{1,2}/, '?')
  }

  // serialize payload and append it to the URL for GET requests
  function serializeData(options) {
    if (options.processData && options.data && $.type(options.data) != "string")
      options.data = $.param(options.data, options.traditional)
    if (options.data && (!options.type || options.type.toUpperCase() == 'GET'))
      options.url = appendQuery(options.url, options.data), options.data = undefined
  }

  $.ajax = function(options){
    var settings = $.extend({}, options || {}),
        deferred = $.Deferred && $.Deferred()
    for (key in $.ajaxSettings) if (settings[key] === undefined) settings[key] = $.ajaxSettings[key]

    ajaxStart(settings)

    if (!settings.crossDomain) settings.crossDomain = /^([\w-]+:)?\/\/([^\/]+)/.test(settings.url) &&
      RegExp.$2 != window.location.host

    if (!settings.url) settings.url = window.location.toString()
    serializeData(settings)
    if (settings.cache === false) settings.url = appendQuery(settings.url, '_=' + Date.now())

    var dataType = settings.dataType, hasPlaceholder = /\?.+=\?/.test(settings.url)
    if (dataType == 'jsonp' || hasPlaceholder) {
      if (!hasPlaceholder)
        settings.url = appendQuery(settings.url,
          settings.jsonp ? (settings.jsonp + '=?') : settings.jsonp === false ? '' : 'callback=?')
      return $.ajaxJSONP(settings, deferred)
    }

    var mime = settings.accepts[dataType],
        headers = { },
        setHeader = function(name, value) { headers[name.toLowerCase()] = [name, value] },
        protocol = /^([\w-]+:)\/\//.test(settings.url) ? RegExp.$1 : window.location.protocol,
        xhr = settings.xhr(),
        nativeSetHeader = xhr.setRequestHeader,
        abortTimeout

    if (deferred) deferred.promise(xhr)

    if (!settings.crossDomain) setHeader('X-Requested-With', 'XMLHttpRequest')
    setHeader('Accept', mime || '*/*')
    if (mime = settings.mimeType || mime) {
      if (mime.indexOf(',') > -1) mime = mime.split(',', 2)[0]
      xhr.overrideMimeType && xhr.overrideMimeType(mime)
    }
    if (settings.contentType || (settings.contentType !== false && settings.data && settings.type.toUpperCase() != 'GET'))
      setHeader('Content-Type', settings.contentType || 'application/x-www-form-urlencoded')

    if (settings.headers) for (name in settings.headers) setHeader(name, settings.headers[name])
    xhr.setRequestHeader = setHeader

    xhr.onreadystatechange = function(){
      if (xhr.readyState == 4) {
        xhr.onreadystatechange = empty
        clearTimeout(abortTimeout)
        var result, error = false
        if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304 || (xhr.status == 0 && protocol == 'file:')) {
          dataType = dataType || mimeToDataType(settings.mimeType || xhr.getResponseHeader('content-type'))
          result = xhr.responseText

          try {
            // http://perfectionkills.com/global-eval-what-are-the-options/
            if (dataType == 'script')    (1,eval)(result)
            else if (dataType == 'xml')  result = xhr.responseXML
            else if (dataType == 'json') result = blankRE.test(result) ? null : $.parseJSON(result)
          } catch (e) { error = e }

          if (error) ajaxError(error, 'parsererror', xhr, settings, deferred)
          else ajaxSuccess(result, xhr, settings, deferred)
        } else {
          ajaxError(xhr.statusText || null, xhr.status ? 'error' : 'abort', xhr, settings, deferred)
        }
      }
    }

    if (ajaxBeforeSend(xhr, settings) === false) {
      xhr.abort()
      ajaxError(null, 'abort', xhr, settings, deferred)
      return xhr
    }

    if (settings.xhrFields) for (name in settings.xhrFields) xhr[name] = settings.xhrFields[name]

    var async = 'async' in settings ? settings.async : true
    xhr.open(settings.type, settings.url, async, settings.username, settings.password)

    for (name in headers) nativeSetHeader.apply(xhr, headers[name])

    if (settings.timeout > 0) abortTimeout = setTimeout(function(){
        xhr.onreadystatechange = empty
        xhr.abort()
        ajaxError(null, 'timeout', xhr, settings, deferred)
      }, settings.timeout)

    // avoid sending empty string (#319)
    xhr.send(settings.data ? settings.data : null)
    return xhr
  }

  // handle optional data/success arguments
  function parseArguments(url, data, success, dataType) {
    if ($.isFunction(data)) dataType = success, success = data, data = undefined
    if (!$.isFunction(success)) dataType = success, success = undefined
    return {
      url: url
    , data: data
    , success: success
    , dataType: dataType
    }
  }

  $.get = function(/* url, data, success, dataType */){
    return $.ajax(parseArguments.apply(null, arguments))
  }

  $.post = function(/* url, data, success, dataType */){
    var options = parseArguments.apply(null, arguments)
    options.type = 'POST'
    return $.ajax(options)
  }

  $.getJSON = function(/* url, data, success */){
    var options = parseArguments.apply(null, arguments)
    options.dataType = 'json'
    return $.ajax(options)
  }

  $.fn.load = function(url, data, success){
    if (!this.length) return this
    var self = this, parts = url.split(/\s/), selector,
        options = parseArguments(url, data, success),
        callback = options.success
    if (parts.length > 1) options.url = parts[0], selector = parts[1]
    options.success = function(response){
      self.html(selector ?
        $('<div>').html(response.replace(rscript, "")).find(selector)
        : response)
      callback && callback.apply(self, arguments)
    }
    $.ajax(options)
    return this
  }

  var escape = encodeURIComponent

  function serialize(params, obj, traditional, scope){
    var type, array = $.isArray(obj), hash = $.isPlainObject(obj)
    $.each(obj, function(key, value) {
      type = $.type(value)
      if (scope) key = traditional ? scope :
        scope + '[' + (hash || type == 'object' || type == 'array' ? key : '') + ']'
      // handle data in serializeArray() format
      if (!scope && array) params.add(value.name, value.value)
      // recurse into nested objects
      else if (type == "array" || (!traditional && type == "object"))
        serialize(params, value, traditional, key)
      else params.add(key, value)
    })
  }

  $.param = function(obj, traditional){
    var params = []
    params.add = function(k, v){ this.push(escape(k) + '=' + escape(v)) }
    serialize(params, obj, traditional)
    return params.join('&').replace(/%20/g, '+')
  }
})(Zepto)

;(function($){
  $.fn.serializeArray = function() {
    var result = [], el
    $([].slice.call(this.get(0).elements)).each(function(){
      el = $(this)
      var type = el.attr('type')
      if (this.nodeName.toLowerCase() != 'fieldset' &&
        !this.disabled && type != 'submit' && type != 'reset' && type != 'button' &&
        ((type != 'radio' && type != 'checkbox') || this.checked))
        result.push({
          name: el.attr('name'),
          value: el.val()
        })
    })
    return result
  }

  $.fn.serialize = function(){
    var result = []
    this.serializeArray().forEach(function(elm){
      result.push(encodeURIComponent(elm.name) + '=' + encodeURIComponent(elm.value))
    })
    return result.join('&')
  }

  $.fn.submit = function(callback) {
    if (callback) this.bind('submit', callback)
    else if (this.length) {
      var event = $.Event('submit')
      this.eq(0).trigger(event)
      if (!event.isDefaultPrevented()) this.get(0).submit()
    }
    return this
  }

})(Zepto)

;(function($){
  // __proto__ doesn't exist on IE<11, so redefine
  // the Z function to use object extension instead
  if (!('__proto__' in {})) {
    $.extend($.zepto, {
      Z: function(dom, selector){
        dom = dom || []
        $.extend(dom, $.fn)
        dom.selector = selector || ''
        dom.__Z = true
        return dom
      },
      // this is a kludge but works
      isZ: function(object){
        return $.type(object) === 'array' && '__Z' in object
      }
    })
  }

  // getComputedStyle shouldn't freak out when called
  // without a valid element as argument
  try {
    getComputedStyle(undefined)
  } catch(e) {
    var nativeGetComputedStyle = getComputedStyle;
    window.getComputedStyle = function(element){
      try {
        return nativeGetComputedStyle(element)
      } catch(e) {
        return null
      }
    }
  }
})(Zepto);
//     Zepto.js
//     (c) 2010-2014 Thomas Fuchs
//     Zepto.js may be freely distributed under the MIT license.

;(function($, undefined){
  var prefix = '', eventPrefix, endEventName, endAnimationName,
    vendors = { Webkit: 'webkit', Moz: '', O: 'o' },
    document = window.document, testEl = document.createElement('div'),
    supportedTransforms = /^((translate|rotate|scale)(X|Y|Z|3d)?|matrix(3d)?|perspective|skew(X|Y)?)$/i,
    transform,
    transitionProperty, transitionDuration, transitionTiming, transitionDelay,
    animationName, animationDuration, animationTiming, animationDelay,
    cssReset = {}

  function dasherize(str) { return str.replace(/([a-z])([A-Z])/, '$1-$2').toLowerCase() }
  function normalizeEvent(name) { return eventPrefix ? eventPrefix + name : name.toLowerCase() }

  $.each(vendors, function(vendor, event){
    if (testEl.style[vendor + 'TransitionProperty'] !== undefined) {
      prefix = '-' + vendor.toLowerCase() + '-'
      eventPrefix = event
      return false
    }
  })

  transform = prefix + 'transform'
  cssReset[transitionProperty = prefix + 'transition-property'] =
  cssReset[transitionDuration = prefix + 'transition-duration'] =
  cssReset[transitionDelay    = prefix + 'transition-delay'] =
  cssReset[transitionTiming   = prefix + 'transition-timing-function'] =
  cssReset[animationName      = prefix + 'animation-name'] =
  cssReset[animationDuration  = prefix + 'animation-duration'] =
  cssReset[animationDelay     = prefix + 'animation-delay'] =
  cssReset[animationTiming    = prefix + 'animation-timing-function'] = ''

  $.fx = {
    off: (eventPrefix === undefined && testEl.style.transitionProperty === undefined),
    speeds: { _default: 400, fast: 200, slow: 600 },
    cssPrefix: prefix,
    transitionEnd: normalizeEvent('TransitionEnd'),
    animationEnd: normalizeEvent('AnimationEnd')
  }

  $.fn.animate = function(properties, duration, ease, callback, delay){
    if ($.isFunction(duration))
      callback = duration, ease = undefined, duration = undefined
    if ($.isFunction(ease))
      callback = ease, ease = undefined
    if ($.isPlainObject(duration))
      ease = duration.easing, callback = duration.complete, delay = duration.delay, duration = duration.duration
    if (duration) duration = (typeof duration == 'number' ? duration :
                    ($.fx.speeds[duration] || $.fx.speeds._default)) / 1000
    if (delay) delay = parseFloat(delay) / 1000
    return this.anim(properties, duration, ease, callback, delay)
  }

  $.fn.anim = function(properties, duration, ease, callback, delay){
    var key, cssValues = {}, cssProperties, transforms = '',
        that = this, wrappedCallback, endEvent = $.fx.transitionEnd,
        fired = false

    if (duration === undefined) duration = $.fx.speeds._default / 1000
    if (delay === undefined) delay = 0
    if ($.fx.off) duration = 0

    if (typeof properties == 'string') {
      // keyframe animation
      cssValues[animationName] = properties
      cssValues[animationDuration] = duration + 's'
      cssValues[animationDelay] = delay + 's'
      cssValues[animationTiming] = (ease || 'linear')
      endEvent = $.fx.animationEnd
    } else {
      cssProperties = []
      // CSS transitions
      for (key in properties)
        if (supportedTransforms.test(key)) transforms += key + '(' + properties[key] + ') '
        else cssValues[key] = properties[key], cssProperties.push(dasherize(key))

      if (transforms) cssValues[transform] = transforms, cssProperties.push(transform)
      if (duration > 0 && typeof properties === 'object') {
        cssValues[transitionProperty] = cssProperties.join(', ')
        cssValues[transitionDuration] = duration + 's'
        cssValues[transitionDelay] = delay + 's'
        cssValues[transitionTiming] = (ease || 'linear')
      }
    }

    wrappedCallback = function(event){
      if (typeof event !== 'undefined') {
        if (event.target !== event.currentTarget) return // makes sure the event didn't bubble from "below"
        $(event.target).unbind(endEvent, wrappedCallback)
      } else
        $(this).unbind(endEvent, wrappedCallback) // triggered by setTimeout

      fired = true
      $(this).css(cssReset)
      callback && callback.call(this)
    }
    if (duration > 0){
      this.bind(endEvent, wrappedCallback)
      // transitionEnd is not always firing on older Android phones
      // so make sure it gets fired
      setTimeout(function(){
        if (fired) return
        wrappedCallback.call(that)
      }, (duration * 1000) + 25)
    }

    // trigger page reflow so new elements can animate
    this.size() && this.get(0).clientLeft

    this.css(cssValues)

    if (duration <= 0) setTimeout(function() {
      that.each(function(){ wrappedCallback.call(this) })
    }, 0)

    return this
  }

  testEl = null
})(Zepto)


code:
// Onload
$(function() {
  window.todo_model = {}, window.todo_presenter = new Mmvp();
  var presenter_dom_identifier = "#viewpen";

  // Setup User Interface Callbacks
  (function ui_callbacks() {
    // Remove Todo Button
    $(document).on("click", "button.remove", function(ev) {
      delete todo_model[$(ev.target).parent().attr('id')];
      todo_presenter.sync(todo_model);
    });
    // Checkmark Todo
    $(document).on("click", "input[type='checkbox']", function(ev) {
      var is_checked = $(ev.target).is(":checked");
      todo_model[$(ev.target).parent().attr("id")]['checked'] = is_checked;
      todo_presenter.sync(todo_model);
    });
    // Add a New Todo
    var item_add_counter = 0;
    $("input").on("keypress", function(ev) {
      if (ev.which == 13) {
        todo_model[item_add_counter++] = {
          text    : $("input[type='text']").val(),
          checked : false
        };
        $("input").val("");
        todo_presenter.sync(todo_model);
      }
    });
  })();

  // Setup Presenter Callbacks
  todo_presenter.set_action({
    empty : function() {
      $("#items-container").remove();
      var no_items_el = $("
");
      no_items_el.append("
No Items!
").append("
Hint: Add a new item.
");
      $(presenter_dom_identifier).append(no_items_el);
      no_items_el.animate({opacity : 1 }, 300, 'ease-in');
    },
    populate : function() {
      $("#no-items").remove();
      $(presenter_dom_identifier).append("
");
    },
    add : function(new_model_key, new_model_value) {
      var checked = new_model_value == true ? "checked" : "";
      var new_div_el = $("
");
      var checkbox = $("<input type='checkbox'>");
      checkbox.attr("checked", (checked ? "" : null));
      var span = $("").text(new_model_value.text);
      var remove_btn = $("<button class='remove'>").html("–");
      new_div_el.attr('id', new_model_key).append(checkbox, span, remove_btn);

      $("#items-container").prepend(new_div_el);
      new_div_el.animate({ opacity: 1 }, 300, 'ease-in');
    },
    remove : function(key_of_removed_item) {
      $("#" + key_of_removed_item).remove();
    },
    update : function(key_of_updated_model, updated_model_value) {
      if (updated_model_value.checked) {
        $("#" + key_of_updated_model).addClass("strikethrough");
      } else {
          $("#" + key_of_updated_model).removeClass("strikethrough");
        }
    }
  });

  // Initialize Mmvp Todo Presenter
  todo_presenter.initialize();
});

license: wtfpl


code:
---
title: Secure Hashed Passwords Using Dwb and Pwdhash
date: 2012-04-25
---
[Password hashing](http://en.wikipedia.org/wiki/Cryptographic_hash_function) services like [PwdHash](https://pwdhash.com) and [SuperGenPass](http://supergenpass.com) allow you enter your password in the password field of any site and then by way of some Javascript your master password is replaced with its hashed counterpart. My problem with these services is that they are fundamentally insecure due to their implementation. Both PwdHash and SuperGenPass rely on replacement of your master password via Javascript after it has already been entered on the site.

Anyone who's spent any time with Javascript knows it would not hard be hard to [retrieve that master password](http://kuza55.blogspot.com/2007/02/attacking-pwdhash-firefox-extension.html) that you entered. Thus, PwdHash and SuperGenPass's hashing implementations only work if you trust the Javascript of every site you visit. How could this ever be classified as a solution to the common household hashing problem?

**A Better Hashing Implementation**:
My solution involves using a browser that can offload the hashing task to another program. Using the browser, [Dwb](http://portix.bitbucket.org/dwb/), you can very easily set it up so that an external script passes in the hashed password to the browser and thus the master password is never exposed.

[hash](https://github.com/mil/configs-and-bins/blob/master/configs/.config/dwb/userscripts/hash) (*~/.config/userscripts/hash*)

```ruby
#!/usr/bin/ruby
require 'uri'
site = (URI).parse(ENV['DWB_URI']).host
password = `zenity --password`
hashedPassword = `node ~/bin/pwdhash.js #{site} #{password}`.chomp!
IO.binwrite(ENV['DWB_FIFO'], "open javascript:document.activeElement.value = '#{hashedPassword}")
```

This hash userscript, to be run from Dwb, essentially just uses [zenity](http://library.gnome.org/users/zenity/stable) ([Xdialog](http://xdialog.free.fr) works here too) to prompt the user for their master password. Then their master password along with the user's current site is run through the commandline tool [pwdhash.js](https://github.com/mil/configs-and-bins/blob/master/bins/pwdhash.js). [pwdhash.js](https://github.com/mil/configs-and-bins/blob/master/bins/pwdhash.js) is just a simple Node.js port I made of the [PwdHash Browser Javascript Implementation](https://pwdhash.com). Once the hashed password is returned from pwdhash.js, Dwb is then told to run some Javascript to insert *only the that hashed password* back into the currently selected password field of the current site.

**Use Case:**
In Dwb, once on a password field, in command mode you type the command ":hash" and a password entry dialog is spawned.

![Pwdhash Password Entry Via Zenity](/assets/blog_img/Secure-Hashed-Passwords-Using-Dwb-and-Pwdhash/pwdhash-password-entry.png)

You type your password in the dialog (generated by zenity) and then once you hit enter your hashed password is inserted into the password field.

![Pwdhash Hashed Password on Google.Com](/assets/blog_img/Secure-Hashed-Passwords-Using-Dwb-and-Pwdhash/pwdhash-password.png)

And there you have it - a more secure hashing implementation using Dwb in combination with PwdHash's algorithm! No long are you exposing your master password to arbitrary Javascript.


code:
---
title: Ruby Socket + Redcarpet = Browser-Based Markdown Preview
date: 2012-04-29
---
So it's finals time and I've been preparing some single page study sheets with [markdown](http://daringfireball.net/projects/markdown/). I use Markdown for generating PDFs for printing ([mkd2pdf](https://github.com/jdodds/mkd2pdf)).
In anycase, I had been using my [Markdown Tree](/projects/markdown-tree) project in order to faciliate a sort of "live-preview" of the documents I send to mkd2pdf. Nothing against [Sinatra](http://sinatrarb.com) but I wanted a lighter solution.  Using Markdown-Tree (and Sinatra) purely for its Markdown rendering capability didn't make sense to me. Really I was just working with Redcarpet and Socket. Sinatra wasn't doing a damn thing for me.

Thus, I felt Sinatra had no place in the task at hand.  What I wanted was a simple commandline tool I could use like *markview.rb somefile.md* and it would give me a live URL on localhost of the markdown file rendered as HTML.

Luckily Ruby provides an excellent [Socket Class](http://www.ruby-doc.org/stdlib-1.9.3/libdoc/socket/rdoc/Socket.html). Combine that with a markdown renderer such as [Redcarpet](http://github.com/tanoku/redcarpet) and you have a simplistic web-based markdown viewing utility. Basically this is just a bit of ruby that interpolates Redcarpet's rendered results with some HTML. Then, along with a HTTP Header, the HTML is served on port 2000. A CSS file for styling is stored in *~/.config/markview*.

```ruby
#!/usr/bin/ruby
require "socket"
require "redcarpet"

def generatePage(filePath)
	#Read style file
	style = File.read("/home/mil/.config/markview/style.css")

	#Use Redcarpet to convert Markdown->HTML
	redcarpet = Redcarpet::Markdown.new(Redcarpet::Render::HTML)
	markdown = redcarpet.render(File.read(filePath))

	#The Content Header Well Be Serving
	header = "HTTP/1.1 200/OK\r\nContent-type:text/html\r\n\r\n"

	#The Content We'll Be Serving
	content = %(
	<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
	"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
	<html xmlns="http://www.w3.org/1999/xhtml">
	<head>
		<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
		<title>Markview : #{filePath}</title>
		<style type="text/css">#{style}</style>
	</head>
	<body>#{markdown}</body>
	)
	return header, content
end

#Start it Up
server = TCPServer.new('localhost', 2000)
loop do
	header, content = generatePage("#{Dir.getwd}/#{ARGV[0]}")
	Thread.start(server.accept) do |session|
		session.print(header)
		session.print(content)
		session.close
	end
end
```

And that's it. Instead of using some graphical tool, you can just replace your markdown preview utility with a single-purpose web server. Redcarpet and Socket are all that is needed. Starting this script up is very snappy in comparison with Sinatra scripts.


code:
---
title: X Cursors and Gumby
date: 2012-05-14
---
I've been playing around with Xlib lately and I found out that X11 comes with a great set of cursors included by default. I was pretty excited when I found out the X developers decided to throw Gumby into the mix! Look at this cursor here:

![Gumby X Cursor Light](/blog/X-Cursors-And-Gumby/gumby_light.gif)
![Gumby X Cursor Dark](/blog/X-Cursors-And-Gumby/gumby_dark.gif)

Yep Gumby is included in Xlib. Check out cursor number 56 in [Xlib Appendix B: X Font Cursors](http://tronche.com/gui/x/xlib/appendix/b) which defines XC_gumby. Gumby can be used in an Xlib program like this:

```c
//Assumes you have previously defined display and window
Cursor cursor;
cursor = XCreateFontCursor(display, 56);
XDefineCursor(display, *window, cursor);
```

[XCreateFontCursor()](http://tronche.com/gui/x/xlib/pixmap-and-cursor/XCreateFontCursor.html), part of [Xlib](http://tronche.com/gui/x/xlib), takes in two parameters: your display (type Display) and the shape for the cursor (type unsigned int). XCreateFontCursor() gives you a variable (of type Cursor) which you can use with [XDefineCursor()](http://tronche.com/gui/x/xlib/window/XDefineCursor.html) to set the cursor for the given display and window.

In anycase, I just wanted to share this and thank the X developers for including Gumby as a standard cursor! He'll come in use.


code:
---
title: Naming Workspaces in i3
date: 2012-05-17
---
I'm not sure how many other WMs have this feature... but naming workspaces is awesome. Using [i3](http://i3wm.org), by way of its [IPC](http://i3wm.org/docs/userguide.html) you can have renamable workspaces. I've found renaming my workspaces to be extremelly helpful in staying on task as I define what I'm going to do in a goal driven manner. See the following small script:

[workspace.rb ](https://github.com/mil/configs-and-bins/blob/master/bins/workspace.rb) *(/home/mil/bin/workspace.rb)*

```ruby
#!/usr/bin/ruby
require 'json'
JSON.parse(%x[i3-msg -t get_workspaces]).each do |workspace|
	if (workspace['focused']) then
		number = workspace['name'].split(/:/)[0]
		newName = "#{number}: #{ARGV[0].chomp}"
		%x[i3-msg 'rename workspace "#{workspace['name']}" to "#{newName}"']
		%x[i3-msg 'bindsym Mod4+#{number} workspace "#{newName}"']
	end
end
```

This just sets whatever was passed in as the new workspace name.Then rebinds the sym. This script can be run by simply opening up Dmenu with a hotkey and typing the command as:

```bash
workspace.rb workspacename
```

And as simple as that the workspace has a name.

<img src="/assets/blog_img/Naming-Workspaces-in-i3/workspace-naming.png" alt="Workspace Renaming in i3"/>

But why would you want to rename a workspace in the first place? Well say you have a certain task at hand that you want accomplish. Cognitivly if you tend to drift, naming the workspace could be a great way to remind yourself of the task at mind. Hell, you could even make these named workspaces persist from session to session if you are handy with xpra as well.


code:
---
title: Window Resizing in Xlib
date: 2012-05-29
---
In many minimal X window managers, the model for resizing windows follows the form of: hold down a modifier key, press the secondary click, and drag. This functionality can be seen in [i3](http://i3wm.org) and [TinyWM](http://incise.org/tinywm.html) among many other X window managers.  But what happens when you're in resize mode, dragging, and hit the border on the left or top side (i.e. the window is as small as it can get vertically/horizontally)? Well you've hit the border.

Below is a snippet of the window manager I'm working on. In my window manager, instead of just hitting the border / threshold when resizing, the window actually flips. So if you start to drag over the border to left or the top, the window will actually invert (not the content but the layout).

```c
//This struct's values are set in the ButtonPress Event
typedef struct {
	XButtonEvent       buttonEvent;
	XWindowAttributes  attributes;
} PointerMotion;
PointerMotion origin;
```

```c
//Within the MotionNotify Event
/* Calculate Difference between current position original click */
int xDifference = event -> xbutton.x_root - origin.button.x_root;
int yDifference = event -> xbutton.y_root - origin.button.y_root;

/* Data for XMoveResize if contracting/expanding normally */
int newX = origin.attributes.x;
int newY = origin.attributes.y;
int newWidth = origin.attributes.width + xDifference;
int newHeight = origin.attributes.height + yDifference;

/* Check if Drag is to the left or top of window, flip window */
if (newWidth == 0) { newWidth = 1; } else if (newWidth < 1 ) {
	newX     = newX + xDifference + origin.attributes.width;
	newWidth = (xDifference * -1) - origin.attributes.width;
}
if (newHeight == 0) { newHeight = 1; } else if (newHeight < 1) {
	newY      = newY + yDifference + origin.attributes.height;
	newHeight = (yDifference * -1) - origin.attributes.height;
}

/* Fire to XMoveResizeWindow */
XMoveResizeWindow(display, origin.button.subwindow,newX, newY, newWidth, newHeight);
```

Basically, if drag difference plus the window's original width/height is less than one, then we're dragging over the border of the top/left. In that case, the width/height is effectivly inverted and the x/y is set accordingly. Note: the check for the height/width == 0 is to prevent X from erroring out.

For a more in context sample see my project, [Simple WM](http://github.com/mil/simple-wm), on GitHub.


code:
---
title: ii - A Better Way to IRC
date: 2012-06-11
---
[ii](http://tools.suckless.org/ii) is a better IRC client created by the great folk at [suckless](http://suckless.org). `ii` is an IRC client that works completely via the filesystem and FIFOs to provide files and folders representing the servers, channels, and chats you are in on IRC. Sound interesting? To me it sure did -- but I found rather sparse documentation on using `ii`. Thus, the creation of this post. `ii` doesn't need much explanation as its usage is basic and it is just 500 lines of C, but it can seem intimidating and impractical for personal use at first glance. However, its a joy once you have `ii` working and realize its simplicity. This guide should get you headed in that path.

So how does one use the `ii` in practicality? The first step is to grab yourself a copy of [ii from suckless](http://tools.suckless.org/ii), extract the `.tar.gz`, and do a standard make/install (I'll assume you can do that much on your own).

Once you've done that, run `ii` for the first time with:

```bash
ii -s irc.freenode.net -n yournick</pre>
```

The folder `~/irc` will be created containing all of your IRC data as such:

```bash
irc/irc.freenode.net
|-- chanserv
|   `-- out
|-- nickserv
|   |-- in
|   `-- out
|-- out
`-- in
```

While `ii` is running that means you are connected to the server. If you look in **~/irc** you should see a folder named `irc.freenode.net` and within that folder, two folders: `chanserv` and `nickserv`. Keep an eye on `~/irc` through usage as all `ii` does is work with the data in that folder.

If you have a registered nickname you'd like to identify with, simply go into the `nickserv` folder, echo to the `in` FIFO, and verify the results with tail like so:

```bash
cd ~/irc/irc.freenode.net/nickserv
echo "identify mysupersecretpassword" > in
tail -n 2 out
```

Assuming you entered the correct password, the nickserv should have identified you. Now your free to enter any channels you might like. The method for joining channels is just like how you talked to the **nickserv**. Here is an example of joining **#testchannel** within **irc.freenode.net**:

```bash
cd ~/irc/irc.freenode.net/
echo "/j #testchannel" > in
```

Now in the `irc.freenode.net` folder you should see a folder named `#testchannel`. Within that folder again, there are `in` and `out` files. Echo something to `in` it will be sent to the channel. The `out` file contains everything you get back from the channel. This should be pretty basic and simple to understand, and that's the point.

So what about viewing the `out` file? cat? No. I don't think you want to be `cat`'ing the `out` file every few seconds to check for new conversation. This is the exact kind of thing `tail` was built for. Additionally tail can be combined another script in order to add syntax highlighting. Another option is using [multitail](http://www.vanheusden.com/multitail) and [some rules](http://nion.modprobe.de/blog/archives/440-Using-the-ii-irc-client.html). However, I didn't want to install another package, so I just wrote [my own script](http://github.com/mil/configs-and-bins/blob/master/bins/regexColorize) for syntax highlighting with `tail`. Here's what my ii `out` files look like when viewed:

[Colorizing ii output with regex-colorize](/assets/blog_img/ii-a-better-way-to-irc/regex-colorize.png)

The colors can be changed easily via my script. Feel free to grab and modify [my regexColorize script from my github]( http://github.com/mil/configs-and-bins/blob/master/bins/regexColorize). I use my `regexColorize` to view my out files like this:

```bash
tail -f -n 500 out | regexColorize
```

And that's about it... A simple setup for using the `ii` irc client. I usually throw my tails piped to `regexColorize` in `tmux`, but you can read about using tmux or screen in many other places.  Finally - if you don't like my methods for using `ii`, other options include: [PCW - Popup Chat Windows](http://bitbucket.org/emg/pcw) or a [Multitail Solution](http://nion.modprobe.de/blog/archives/440-Using-the-ii-irc-client.html). Regardless, I hope I will have made a few irssi, xchat, etc fans convert to `ii`.


code:
---
title: Incremental Search in Bash and ZSH
date: 2012-06-24
---
Every once in a while I stumble upon something on my own computer I am amazed by. Easter eggs? No, more like me not fully looking into functionality. In anycase, maybe I'll expose some Bash and Zsh users to this feature as maybe there are some that are clueless like I was.

**Incremental History Search** autocompletes your command as you type based on your history file. All you do is hit **Control-R** in a Bash or Zsh shell to trigger this functionality and you will be greeted with a prompt that looks something like this:

As you start to type your prompt will match the last command from your history. If you want to see earlier matches from your history, just continually press **Control-R**.

Simple, time saving, and a great feature!


code:
---
title: b(ar) a(in't) r(ecursive)
date: 2012-07-29
---
[b(ar) a(in't) r(ecurisve)](http://github.com/LemonBoy/bar) or bar for short is a new XCB based bar by the Lemon Man. Think dzen2 or conky, only zero bloat. Bar is only what's needed and nothing more. Under 300 lines of C, bar is a quality piece of software that I am glad to throw in my .xinitrc.

So how does bar work? Basically it just reads STDIN and draws the read text to an XCB bar. Configuration is along the lines of dwm and other minimalist software. You set your configuration in bar's config.h and it's baked in at compile time.  Within the config.h, you can specify: ten colors which can be used to visually style the bar, your desired font, and the height of the bar.

Other than that, for formatting text you can left, center, and right align text and style your bar's text foreground and background colors with your defines from the config.h.

Simple, minimal, and functional. If only all software were like this.


code:
---
title: Linux on a Macbook
date: 2012-07-26
---
I got home the two nights ago to discover the screen of my Thinkpad cracked. A shame, but atleast I have a new server. In anycase, my only other spare computer currently happens to be my old 13" Duo Core White Macbook.

Onto Linux on a Mac, once again. Some advice to anyone trying to get a Non-Mac OS onto a Mac, use MBR and save yourself the EFI / GPT headaches. I had installed Linux on this Macbook before, and again this past time I felt I had to put myself through the pain of attempting GPT on the Macbook. The Arch Wiki page on Macbooks advises strongly against MBR, possibly beacuse its just the older schema. However, I think the pragmatic approach applies here. Simply, MBR just works, GPT I havn't been able to get to work. It seems other have succeeded with GPT, however for some reason my Macbook continually fails to cooperate.

So after a few failed GPT installs, and finally getting a booting install with MBR/Grub2, I was onward. I still need to bless my boot partion (thanks Apple), but for now I can wait 30 seconds for Grub to kick in. Other than that it works fine!


code:
---
title: Extending Io's Objects
date: 2012-08-11
---
Recently, I've been working in a little language called [Io](http://iolanguage.com). Io is a prototype-based programming language that feels a lot like Smalltalk. Io takes the object message passing style very seriously. Resulting, everything in Io is an object. Io's syntax is very succint and incredibly extendable. It's very meta, and thats a good thing.

In Io, when you create a string, it is of type **Sequence** which is a more broad object providing a sequence of data elements to manipulate. The fact that a string is really just a **Sequence** is good, but can be troubling. For example, how does one determine the character at a certain location of a **Sequence**? The **Sequence**'s handy **at** message will just give you the integer of the entry at a specific location in the sequence:

```io
Io> myString := "abcdefgh"
==> abcdefgh
Io> myString at(4)
==> 100
```

Well I don't think 100 was what I was looking for. However, 100 being a **Number** object, can use the **asCharacter** message to find out what character 100 represents in ASCII.

```io
Io> 100 asCharacter
==> d
```

But this is all very round about. How about adding our own atCharacter() method to Sequence to make the process simpler:

```io
Io> Sequence charAt := method(pos, thisContext at(pos) asCharacter)
==> method(pos, thisContext at(pos) asCharacter)
```

Io has no problem with this as why should you not be able to extend objects as such? After you add the **charAt** method to **Sequence**, you can more simply determine the character at a specific location in a string:

```io
Io> myString := "abcdefgh"
==> abcdefgh
Io> myString charAt(3)
==> d
```

This is the kind of thing that makes Io very badass.


code:
---
title: Mplayer's FIFO
date: 2012-08-14
---
I was incredibly excited when I found out that mplayer can be controlled via a FIFO. It wasn't a huge suprise as ofcourse there must be some IPC for mplayer, but still, this is awesome.

First make the FIFO for mplayer:

```bash
mkfifo /home/mil/fifos/mplayer
```

Now, you can control mplayer via the FIFO by specifying a file with -input:

```bash
mplayer -input file=/home/mil/fifos/mplayer somemediafiles
echo "pt_step 1" > /home/mil/fifos/mplayer
echo "pause" > /home/mil/fifos/mplayer
```

Let's see all the available commands that the FIFO accepts:

```bash
mplayer -input cmdlist
```

And finally if you don't want to have to use the -input file= syntax every time you start mplayer, you can have mplayer by default open the FIFO by specifying the path to your FIFO in your ~/.mplayer/config:

```bash
> cat ~/.mplayer/config
# mplayer config file
input=file=/home/mil/fifos/mplayer
```

And that's all. Use mplayer's FIFO. Here's a link to [all the commands](http://www.mplayerhq.hu/DOCS/tech/slave.txt) the FIFO accepts.


code:
---
title: Hackerschool
date: 2012-08-17
---
Well [Hackerschool](http://www.hackerschool.com) is nearly over now and the next batch application deadline is nearing. If you're a potential applicant wondering: "Is Hackerschool for me?" -- then maybe this post about my experience will help you figure that out.

Hackerschool is an unstructured programming education program done right. The good folks who facilitate Hackerschool do not tell you to build x, or today we're going to learn y, but rather -- only you decide what you'll work on. How could this ever work? Well simply put, Hackerschool is not something you do to get a degree, a certificate, or a job. The people who do Hackerschool are legitimately passionate about programming. And the only reason you would or should want to do Hackerschool is because you too are passionate about programming and want to program for 3 months straight with no distractions.

And hell, you have to be passionate about programming to spend 3 months doing nothing but programming and not getting paid for it. And that is the essence of Hackerschool. You can occasionally hack around on off time, but committing along with dozens of other programmers to do nothing but hack for 3 months straight takes serious dedication.

So what do people actually do and hack on in Hackerschool? Tons of things: some learn languages, others build languages, some learn frameworks, others build frameworks, some write scrapers, others contribute to existing libraries, some write apps, others write kernel modules... and this list goes on. The list goes on because what you do in Hackerschool is entirely up to you. For me, I spent my time learning C, building a window manager, and doing some Ruby, Smalltalk, Lisp, and Io. Additionally I contributed to a lot of the software I use on a daily basis.

Finally, being in Hackerschool is a lot like being a hacker. It is a lifelong commitment, as long as you call yourself a hacker, you should be hacking. For the students and alumni of Hackerschool, there is a phrase that gets passed around a lot: "never graduate". Hackers don't stop hacking just because "Hackerschool" is over, in fact hackers never stop hacking. Hackers contribute to open source projects, learn things, and build cool things. So should you do Hackerschool? Well -- are you a hacker?


code:
---
title: My New Alarm Clock
date: 2012-10-13
---
Sometimes I can't get myself out of bed and to a conscious state before a certain hour. However, if there is something to think about, a challenge to face, or simply just a blaring 22 inch monitor flicking 600 times every minute while blaring music is playing -- I tend to extract myself from bed. Without further ado, I present my new alarm clock:

[xcalib](http://xcalib.sourceforge.net) + [xset](http://linux.die.net/man/1/xset) + [slock](http://tools.suckless.org/slock) + [mplayer](http://www.mplayerhq.hu) + [cron](http://en.wikipedia.org/wiki/Cron) = a wonderful seizure-style start to your day!

Before I go to sleep, I kill my display with goodnight:

```bash
alias goodnight='xset dpms force off'
```

And then I have a script that I call wakeup:

```ruby
#!/usr/bin/env ruby
ENV['DISPLAY'] = ':0'
%x[xset dpms force on]

Thread.new do
    %x[slock]
    %x[xcalib -a clear]
    exit
end

Thread.new do
    loop do
        %x[mplayer ~/.alarm.mp3]
    end
end

loop do
    %x[xcalib -a -invert]
    sleep 0.2
end
```

I'll see you at 9 AM in the morning cron. In crontab -e:

```bash
0 9 * * * /home/mil/bin/x/wakeup
```

Nice, I'm awake and there's a 22 inch screen inverting colors at a rate of 10 times per second illuminating my room while blaring music is playing. I have to type my password for slock to stop this madness. Annoying enough to make me get out of bed? You bet.


code:
---
title: Autojump
date: 2012-10-15
---
[Autojump](http://github.com/joelthelion/autojump) is an ingenious piece of software that maintains a database of the most frequent directories you use from command line. Then you can simply jump to those directories by short hand. For example, I frequently vist the directory */home/mil/code/repos/github/foo-wm*. Typing this out with *cd* every time I launch a new terminal would normally either require: the combination of me hitting the first few letters with a lot of tabs or a backwards search with control-r. However autojump is far simpler:

```bash
j github/foo
```

It's that easy and it works damn well. If I ever find myself repetitively hitting tab, I stop and figure out where I'm going and go there with *j*. Thank you [joelthelion](http://github.com/joelthelion) for a piece of true quality software.


code:
---
title: A Simpler TODO List
date: 2013-01-15
---
There are likely thousands of TODO list "applications" and "systems" out there, however, I think we've forgotten the most simple and elegent solution:

In your **.bashrc** or **.zshrc**:

```bash
cat ~/.TODO
```

Then just maintain a file in your home directory called **.TODO** with all the things you need to do.

Every time you launch a new shell you'll be reminded of what you need to do. Do you really need another piece of software to "manage" your TODO list?


code:
---
title: Restoring Rockbox Root on Clip+
date: 2013-01-16
---
Recently my Sansa Clip+ died on me randomly. I had Rockbox installed for about two years and then one day when I booted it up it just said "File not found". Makes sense, flash can be temperamental.  In anycase, for any of yall in the same position, here's the quick restore procedure to get your Rockbox root fs back and booting:

Plug in your Clip+ and wipe the partition table, make a new partition, format it vfat, and mount it:

```bash
fdisk /dev/sdb (your device)
  --> proceed to delete (d) any existing partitions,
    (in my case there were none)
  --> make a new partition (n), set filesystem type(t) to b
  --> write (w) out
mkfs.vfat /dev/sdb1 (your device partition)
mkdir /mnt/clip
mount /dev/sdb1 /mnt/clip
```

Now you've got a partition to work with, so proceed with normal Rockbox setup procedure. Download the Rockbox firmware and copy it over to your clip:

```bash
wget http://build.rockbox.org/data/rockbox-sansaclipplus.zip
unzip rockbox-sansaclipplus.zip
mv .rockbox /mnt/clip
```

Then, patch and copy over the bootloader the manual way (GUI didn't work for me):

```bash
wget http://mp3support.sandisk.com/firmware/clipplus/clipplus01.02.16.zip
wget http://download.rockbox.org/bootloader/sandisk-sansa/clipplus/bootloader-clipplus.sansa
wget http://download.rockbox.org/bootloader/sandisk-sansa/mkamsboot/linux-x86-32/mkamsboot
unzip clipplus01.02.16.zip
./mkamsboot clppa.boot bootloader-clipplus.sansa patched.bin
cp patched.bin /mnt/clip/clppa.bin
umount /mnt/clip
```

Unplug the Clip+ and Rockbox should be working again.


code:
---
title: Graphical REPLs?
date: 2013-01-29
---
Where are all the Graphical Read Evaluate Print Loop Interfaces? Where is the graphical shell? There was [TermKit](http://github.com/unconed/TermKit) a bit back, but TermKit relied on Node.JS plus Webkit.. which was a fragile solution. Though, conceptually, TermKit was right on target.  But what might the "ideal" graphical REPL look like?

Is a HTML DOM tree styled with CSS adequate to represent *any* output?  Does it make sense to wrap it all in Webkit? How do we hook into files?  Or do we need a new way to represent the output of command line applications?  A new shell with a new objects system too?

Say we build this Graphical REPL.. Will the line then blur between graphical and command-line-applications? Or are graphical and command line enviroments destined to stay divided?


code:
---
title: Gulp for Sitebuilds
date: 2014-12-25
---

[Gulp](http://gulpjs.com), is a tiny library of utility functions (`src`, `dest`, `task`, and `watch`) that plug and play nicely with node streams.  As such, if your a stream fan, or simply have ever used Unix pipes, Gulp will make you feel right at home while helping you to architect sitebuilds.

As far as `Gulpfile`'s go, structure your tasks, or task-generating logic however you wish.  What I found to work for me on the sitebuild for [userbound.com](http://userbound.com) was to break my logic into small `exports`-style modules and let [my Gulpfile](https://github.com/mil/userbound.com-gulp/blob/master/Gulpfile.js) play the role of master `require`-er:

```js
#!/usr/bin/env node
'use strict';
// Require Modules
var gulp = require('gulp');
var $ = require('gulp-load-plugins')({
  pattern: '*',
  rename: {
    'underscore': '_',
    'yaml-front-matter': 'yaml_extractor',
    'gulp-front-matter': 'fem',
    'gulp-ruby-sass': 'sass'
  }
});

// Require Globals (vars) and Utils (fns)
var globals = require('./lib/globals')($);
var util    = require('./lib/util')($, globals);
var mutators = require('./lib/mutators')($, globals);

// Require Tasks
$._.each($.fs.readdirSync('./lib/tasks'), function(module) {
  require('./lib/tasks/' + module)(gulp, $, util, mutators, globals);
});
```

This way, I keep my tasks nice, small, and discrete.  [Jekyll](http://jekyllrb.com) for sitebuilds always felt like a hack; but [Gulp](http://gulpjs.com) for sitebuilds feels great.

_Thanks Gulp_.


code:
---
title: Pango Markup in i3bar
date: 2015-03-20
footnotes:
    - This is great, because previously if you wanted to style the output of i3status or your status_command in i3, you were limited to setting only foreground colors. Now you have all of Pango markup at your disposal.
    - While nothing close to the styling available in browser or with candybar, this is a monumental improvement from i3bar's previous styling support.
    - Pango markup supports a number of text attribute styling options, including background, forgroung color, and underlining.
---

Since a little over a month ago, [i3bar](http://i3wm.org/i3bar/manpage.html) supports inline [pango markup](https://github.com/i3/i3/issues/1468) for styling your statusline and workspaces1.  So after figuring this out, this past weekend I took some time to redo my statusline.

I wrote a small [ruby script](https://github.com/mil/home/blob/master/Scripts/Utilities/json-bar) to serve my i3 statusline command which generates little aesthetic blocks (styled with Pango markup) for time, weather, network, audio level, and power... looking like:

![Pango Markup in i3Bar screenshot](/assets/blog_img/Pango-Markup-in-i3bar/bar.png)

Each block I define as a hash, specifying symbol, color, and the function which returns the data to display:

```ruby
blocks = [
    {
        :symbol => "↬",
        :color=> "#530067",
        :text => fetchers.network
    }, ...
]
```

Where `fetchers` holds some functions for retrieving system data:

```ruby
class InfoFetchers
  def network
    %x[netctl list].split("\n").select { |n|
      n if n[0] == "*"
    }.first.gsub!("* ", "")
  end ...
end
fetchers = Info_Fetchers.new
```

Each block gets passed through a `map` function to stylize with Pango 3. This way I get a consistent feel for each block and I keep my code DRY. The final output is assembled as `JSON` and passed onto `i3bar`:

```ruby
blocks.map do |f|
   text = [
       "<span rise='10000' size='large' underline_color='#ffffff' underline='double'>",
      "<span bgcolor='#{f[:color]}' fgcolor='#ffffff'> #{f[:symbol]} </span>",
      "</span>",

      "<span rise='10000' size='8900' underline='double' underline_color='#ececec'>",
      "<span fgcolor='#2b2b2b' bgcolor='#f9f9f9'> #{f[:text]} </span>",
      "</span>"
    ].join

    {
      :separator => false,
      :separator_block_width => 10,
      :align => 'left',
      :min_width => 0,
      :full_text => text,
      :markup => 'pango'
    }
end.to_json
```

So yeah -- Pango + i3bar is nice. Feel free to [steal my status bar generating script](https://github.com/mil/home/blob/master/Scripts/Utilities/json-bar) featuring the block aesthetic. It took me a while to get Pango to cooperate, so I hope I'll save some folks some effort!

Thanks to [acrisci](https://github.com/acrisci) who was the one who dropped Pango into [i3](https://i3wm.org/) upstream.


code:
---
title: A Map Function for Sass
date: 2015-05-09
footnotes:
    - Luckily however Sass has excellent documentation, so when search fails, that's a great place to start.
    - Since you can't pass functions as parameters in Sass; in my implementation I use call to accomplish the same effect. The downside is that the function name has to be passed to the final map_function quoted.
    - A map function, given a list and a function name, returns a new list containing the function called against each entry.  For primer on what a map function is.. further than this baseline explanation, refer here.
---
[Sass](http://sass-lang.com/) doesn't have a built in map function for lists and furthermore online searches on the subject will yield you tons of information about Sass maps... and next to nothing about how to make a map function in Sass1.

So here a basic implementation2 I worked out for a simple map function in Sass3:

```scss
@function map_function($list, $function_name)
  $return_list: ()

  @for $index from 1 through length($list)
    $call_result: call($function_name, nth($list, $index))
    $return_list: append($return_list, $call_result)

  @return $return_list
```

And for those of you who like all those extra curly brackets, the SCSS equivalent is:

```scss
@function map_function($list, $function_name) {
  $return_list: ();
  @for $index from 1 through length($list) {
    $call_result: call($function_name, nth($list, $index));
    $return_list: append($return_list, $call_result);
  }
  @return $return_list;
}
```