<!DOCTYPE html>
<html>

  <head lang="en">
    <meta charset="utf-8">
    <title>Custom Plunker</title>
    <script src="craft.js"></script>
  </head>
  
  <body>
  
    <pre id="log"></pre> 
    <script>
      var log = function(message){
        document.getElementById("log").appendChild(document.createTextNode(message + "\n"));
      }
      function eachObject(obj) {
        for (key in obj) { log(key); } // "myMethod", "a", "b"
      }

      function eachArray(ary) {
        for (key in ary) { log(key); } // "myMethod", "0", "1", "2"
      }

      eachObject({ a: 1, b: 2 });
      eachArray([ 1, 2, 3 ]);
      
    </script>
  </body>
</html>
/*!
  Craft.js
  1.1.2 
*/



;(function(window, document){


  var Craft = Craft || { version : "1.1.2" }
    , hasOwn = Object.prototype.hasOwnProperty
    , extend

  function typeOf(object){
    var type = typeof object
    if(object instanceof RegExp) return "regexp"
    if(object === null) return "null"
    if(object instanceof Array) return "array"
    return type
  }

  function toArray(list, start){
    var array = []
      , index = start || 0
      , length = list.length
    for(;index < length; index++) array.push(list[index])
    return array
  }

  extend = Object.extend = function(object, source, noCall){
    var index
    if(!noCall && typeOf(source) == "function") source = source()
    for(index in source) if(hasOwn.call(source, index)) object[index] = source[index]
    return object
  }

  extend(window, {
    Craft : Craft
  })

  extend(Object, {
    typeOf : typeOf
  })

  extend(Array, {
    convert : toArray
  })



  extend(Array.prototype, function(){

    function each(fn, context){
      var self = this
        , index = 0
        , length = self.length

      for(;index < length; index++) fn.call(context, self[index], index, self)

      return self
    }

    function collect(fn, context){
      var self = this
        , mapped = Array(self.length)
        , index = 0
        , length = self.length

      for(;index < length; index++) mapped[index] = fn.call(context, self[index], index, self)

      return mapped
    }

    function select (fn, context){
      var self = this
        , filtered = []
        , index = 0
        , length = self.length

      for(;index < length; index++) if(fn.call(context, self[index], index, self)) filtered.push(self[index])

      return filtered
    }

    function fold(fn, initial){
      var self = this
        , hasInit = arguments.length != 1
        , reduced = hasInit ? initial : self[0]
        , index = hasInit ? 0 : 1
        , length = self.length

      for(;index < length; index++) reduced = fn(reduced, self[index], index, self)
      return reduced
    }

    function find(search, start){
      var self = this
        , index = start || 0
        , length = self.length
      for(;index < length; index++) if(self[index] === search) return index
      return -1
    }

    function contains(value){
      return !!~this.find(value)
    }

    function pluck(property){
      var self = this
        , plucked = Array(self.length)
        , index = 0
        , length = self.length

      for(;index < length; index++) plucked[index] = self[index][property]

      return plucked
    }

    function isEmpty(){
      var self = this
        , index = 0
        , length = self.length
      for(;index < length; index++) return false
      return true
    }

    function clone(){
      return this.concat()
    }

    function clean(){
      var self = this
        , cleaned = []
        , index = 0
        , length = self.length
        , item
      for(;index < length; index++) {
        item = self[index]
        if(typeof item != "number" && !item) continue
        if(typeof item == "object" && item.length === 0) continue
        cleaned.push(item)
      }
      return cleaned
    }

    function intersect(values){
      var self = this
        , result = []
        , index = 0
        , length = self.length
        , item
      for(;index < length; index++) {
        item = self[index]
        if(values.contains(item)) result.push(item)
      }
      return result
    }

    function difference(values){
      var self = this
        , result = []
        , index = 0
        , length = self.length
        , item
      for(;index < length; index++) {
        item = self[index]
        if(!values.contains(item)) result.push(item)
      }
      return result
    }

    function invoke(fn){
      var self = this
        , index = 0
        , length = self.length
        , args = toArray(arguments, 1)
        , result = []
      for(;index < length; index++) result[index] = (typeOf(fn) == "string" ? Element.methods[fn] : fn).apply($(self[index]), args)
      return result
    }


    function group(){
      return this.fold(function(a,b){ return a.concat(b) }, [])
    }

    return {
      each: each,
      clone: clone,
      collect: collect,
      select: select,
      fold: fold,
      group: group,
      find: find,
      contains: contains,
      pluck: pluck,
      isEmpty: isEmpty,
      invoke: invoke,
      clean: clean,
      intersect: intersect,
      difference: difference
    }
  })


  function Hash(object){
    var self = this
      , length
    
    if(!(self instanceof Hash)) return new Hash(object)
    extend(self, object, true)
    if(object && (length = object.length)) self.length = length
  }
  
  extend(Hash.prototype, function(){
    
    function each(fn, context){
      var self = this
        , index
      for(index in self) if(hasOwn.call(self, index)) fn.call(context, self[index], index, self)
      return self
    }
    
    function clone(){
      return new Hash(this)
    }
    
    function keys(){
      var array = []
      this.each(function(item, index){array.push(index)}) 
      return array
    }
    
    function values(){
      var array = []
      this.each(function(item){ array.push(item) })
      return array
    }
    
    function get(key){
      return this[key]
    }
    
    function set(key, value){
      var self = this
      self[key] = value
      return self
    }
    
    function isEmpty(){
      var self = this
        , index
      for(index in self) if(hasOwn.call(self, index)) return false
      return true
    }
    
    function toQueryString(){
      var self = this
        , queryString = ""
      self.each(function(item, index){
        if(!item) return
        queryString += index + "=" + [].concat(item).join("&" + index + "=") + "&"
      })
      queryString = queryString.slice(0, -1)
      return "encodeURI" in window ? encodeURI(queryString) : escape(queryString)
    }
    
    return {
      each: each,
      clone: clone,
      keys: keys,
      values: values,
      get: get,
      extend: extend,
      set: set,
      isEmpty: isEmpty,
      toQueryString: toQueryString
    }
  })
  
  extend(window, {
    Hash: Hash
  })


  extend(Function.prototype, {
    bind : function(context){
      var self = this
        , args = toArray(arguments, 1)
      return function(){
        return self.apply(context, args.concat(toArray(arguments)))
      }
    },
    curry : function(){
      var self = this
        , args = toArray(arguments)
      
      return function(){
        return self.apply(this, args.concat(toArray(arguments)))
      }
    },
    delay : function(time){
      var self = this
        , args = toArray(arguments, 1)
      return window.setTimeout(function(){
        self.apply(undefined, args)
      }, time * 1000)
    },
    every : function(time){
      var self = this
        , args = toArray(arguments, 1)
      return window.setInterval(function(){
        self.apply(undefined, args)
      }, time * 1000)
    }
  })


  extend(String.prototype, {
    parseJSON : function(){
      var self = this
      return "JSON" in window ? JSON.parse(self) : (new Function("return " + self))()
    },
    trim : function(){
      return this.replace(/^\s+|\s+$/g, "")
    },
    camelize : function(){
      return this.replace(/-\D/g, function(match, i){
        return i !== 0 ? match.charAt(1).toUpperCase() : match.charAt(1)
      })
    },
    capitalize : function(){
      return this.replace(/^\w|\s\w/g, function(match){
        return match.toUpperCase()
      })
    }
  })  


  function Ajax(params){
    var request = "XMLHttpRequest" in window ? new XMLHttpRequest() : ActiveXObject("Microsoft.XMLHTTP")
      , self = this
  
    if(!(self instanceof Ajax)) return new Ajax(params)
    
    extend(self, params)
    extend(self, {request : request})
    
    if(!self.method) self.method = "GET"
    if(typeOf(self.async) != "boolean") self.async = true
    
    self.request.onreadystatechange = function(){
      var readyState = self.request.readyState
        , status, loading, success, error
      
      if(readyState == 2 && (loading = self.loading)) loading()
      if(readyState == 4 && (status = self.request.status) && ((status >= 200 && status < 300) || status == 304) && (success = self.success)) success(self.request.responseText)
      if(readyState == 4 && (status = self.request.status) && ((status < 200 || status > 300) && status != 304) && (error = self.error)) error(status)
    }
  }
  
  extend(Ajax.prototype, Hash.prototype)
  
  extend(Ajax.prototype, {
    update : function(){
      var self = this
        , method = self.method
        , request = self.request
        , url = self.url
        , xml = self.xml
        , async = self.async
        , query = self.query
        , headers = self.headers
        , index
        
      request.open(method, url, async)
      
      if(method == "POST") {
        request.setRequestHeader("X-Requested-With", "XMLHttpRequest")
        request.setRequestHeader("Content-type", "application/x-www-form-urlencoded")
      }
      for(index in headers) if(hasOwn.call(headers, index)) request.setRequestHeader(index, headers[index])
      
      request.send(query || null)
      if(!async) return request[xml ? "responseXML" : "responseText"]
    },
    periodicalUpdate : function(time){
      var self = this
      return (function(){ self.update() }).every(time)
    }
  })

  extend(window, { Ajax: Ajax })


 var NATIVE_ELEMENT = "Element" in window
   , NATIVE_EVENT = "Event" in window
   , classList = "classList" in document.createElement("i")
   , formElementsRegExp = /SELECT|INPUT|TEXTAREA|BUTTON/
   , checkRegExp = /checkbox|radio/
   , eventListener = "addEventListener" in window
   , Element = NATIVE_ELEMENT ? window.Element : {}

 if(!NATIVE_ELEMENT) extend(window, {
    Element : Element
 })

 function $(element) {
   if(!element) return document.createElement("div")
   if(typeOf(element) == "string") return $(document.getElementById(element) || document.createElement("div"))
   if(element.nodeType == 11) return extend(element, Element.methods)
   if(NATIVE_ELEMENT) return element
   else return extend(element, Element.methods)
 }

 extend(Craft, {
   noConflict : function(){
     if(window.$ == $) window.Craft.$ = $
     return $
   }
 })

 extend(window, {
   $ : $
 })

 if(!NATIVE_EVENT) extend(window, {
   Event : {}
 })

 extend(Event, {
   stop : function(eventObject){
     eventObject = eventObject || window.event
     if(eventListener){
        eventObject.preventDefault()
        eventObject.stopPropagation()
     } else {
       eventObject.returnValue = false
       eventObject.cancelBubble = true
     }
   }
 })

 function buildNodes(string){
   var el = document.createElement("div")
     , fragment = document.createDocumentFragment()
     , length
     , childNodes
     , index = 0
   el.innerHTML = string
   childNodes = toArray(el.childNodes)
   length = childNodes.length
   if(length == 1) return childNodes[0]
   for(;index < length; index++) fragment.appendChild(childNodes[index])
   return fragment
 }

 function toNodes(object){
   var nodeType = object.nodeType
   if(typeOf(object) == "string") return buildNodes(object)
   if(nodeType && (nodeType == 1 || nodeType == 11 || nodeType == 3)) return object
   else return document.createTextNode("")
 }

  extend(Element, {
    extend : function(object){
      extend(Element.methods, object)
      if(NATIVE_ELEMENT) extend(Element.prototype, object)
    },
    create : function(tag, properties){
      var element = document.createElement(tag)
        , index
      for(index in properties) if(hasOwn.call(properties, index)) element[index] = properties[index]
      return $(element)
    },
    from : function(string){
      return $(buildNodes(string))
    },
    createFragment : function(){
      return $(document.createDocumentFragment())
    },
    ready : function(func){
      if (/in/.test(document.readyState) || !document.body) (function(){ Element.ready(func) }).delay(0.01)
      else func.delay(0)
    },
    getById : function(id){
      return $(id)
    },
    getByTag : function(tag){
      return toArray(document.getElementsByTagName(tag)).collect(function(item){ return $(item)})
    },
    getByClass : function(klass){
      if("getElementsByClassName" in document){
        return toArray(document.getElementsByClassName(klass)).collect(function(item){ return $(item)})
      } else {
        return toArray(document.getElementsByTagName("*")).collect(function(item){return $(item) }).select(function(item){return item.hasClass(klass)})
      }
    }
  })

  Element.methods = {
    get : function(key){
      return this[key]
    },
    set : function(key, value){
      var self = this
      self[key] = value
      return self
    },
    insert : function(object){
      var self = this
        , nodeType = object.nodeType
        , top
        , bottom
        , before
        , after
        , parent
        , nextSibling
        , firstChild
      if(!object) return this
      if(typeOf(object) == "string") return self.insert({ bottom : toNodes(object) })
      if(nodeType && (nodeType == 1 || nodeType == 11 || nodeType == 3)) return self.insert({ bottom : object })

      if(top = object.top) {
        if(firstChild = self.firstChild){
          self.insertBefore(toNodes(top), firstChild)
        } else {
          self.appendChild(toNodes(top))
        }
      }
      if(bottom = object.bottom) self.appendChild(toNodes(bottom))
      if(before = object.before) {
        if(parent = self.parentNode) parent.insertBefore(toNodes(before), self)
      }
      if(after = object.after) {
        if(parent = self.parentNode) {
          if(nextSibling = self.nextSibling){
            parent.insertBefore(toNodes(after), nextSibling)
          } else {
            parent.appendChild(toNodes(after))
          }
        }
      }
      return self
    },
    appendTo : function(container){
      var self = this
      Element.methods.insert.call(container, {
        bottom : self
      })
      return self
    },
    prependTo : function(container){
      var self = this
      Element.methods.insert.call(container, {
        top : self
      })
      return self
    },
    empty : function(){
      var self = this
        , childNodes = self.childNodes
        , index = childNodes.length
      while(index--) self.removeChild(childNodes[index])
      // enable insertBefore with firstChild, event if empty.
      self.appendChild(document.createTextNode(""))
      return self
    },
    remove : function(){
      var self = this
        , parent
      if(parent = self.parentNode) parent.removeChild(self)
      return self
    },
    css : function(object){
      var self = this
        , style = self.style
      if(!object) return style.cssText
      if(typeOf(object) == "function") object = object.call(self, style)
      Hash(object).each(function(item, index){
        style[index.camelize()] = typeOf(item) == "number" && item !== 0 ? item + "px" : "" + item
      })
      return self
    },
    getChildren : function(){
      var self = this
        , children = self.children
        , length = children.length
        , result = Array(length)
        , index = 0
      for(;index < length; index++) result[index] = $(children[index])
      return result
    },
    getParent : function(){
      var parent = this.parentNode
      return parent ? $(parent) : null
    },
    getSiblings : function(){
      var self = this
        , parent = self.getParent()
      return parent && parent.getChildren().select(function(item){
        return item != self
      })
    },
    classNames : function(){
      var self = this
        , className
      if (classList) return toArray(self.classList)
      if (className = self.className) return className.split(" ")
      return []
    },
    hasClass : function (string){
      var self = this
      if(classList) return self.classList.contains(string)
      return self.classNames().contains(string)
    },
    addClass : function(classes){
      var self = this
        , index, classNames, item

      classes = classes.split(" ")
      index = classes.length

      if(classList) while(index--) self.classList.add(classes[index])
      else {
        classNames = self.classNames()
        while(index--) {
          item = classes[index]
          if(classNames.contains(item)) continue
          classNames.push(item)
        }
        self.className = classNames.join(" ")
      }
      return self
    },
    removeClass : function(classes){
      var self = this
        , index

      classes = classes.split(" ")
      index = classes.length

      if(classList) while(index--) self.classList.remove(classes[index])
      else self.className = self.classNames().difference(classes).join(" ")
      return self
    },
    toggleClass : function(classes){
      var self = this
        , index, item

      classes = classes.split(" ")
      index = classes.length

      if(classList) while(index--) self.classList.toggle(classes[index])
      else {
        while(index--){
          item = classes[index]
          if(self.hasClass(item)) self.removeClass(item)
          else self.addClass(item)
        }
      }
      return self
    },
    getValue : function(){
      var self = this
        , tag = self.nodeName
        , options
      if(!formElementsRegExp.test(tag) || self.disabled) return
      if(tag == "SELECT"){
        options = toArray(self.options)
        if(self.multiple) return options.select(function(item){return !!item.selected}).pluck("value")
        return options[self.selectedIndex].value
      }
      if(checkRegExp.test(self.type)) return self.checked ? self.value : undefined
      return self.value
    },
    setValue : function(value){
      var self = this
        , tag = self.nodeName
      if(!formElementsRegExp.test(tag) || self.disabled) return self
      if(tag == "SELECT"){
        options = toArray(self.options)
        if(self.multiple) options.each(function(item){item.selected = false})
        ;[].concat(value).each(function(item){
          var index = typeOf(item) == "number" ? item : options.pluck("value").find(item)
          if(index > -1 && options.length > index) options[index].selected = true
        })
      } else {
        self.value = value
      }
      return self
    },
    serialize : function(){
      var self = this
        , result = new Hash()
      toArray(self.elements).each(function(item){
        var value = Element.methods.getValue.call(item)
          , name = item.name
        if(typeOf(value) == "undefined" || !name) return
        if(name in result) {
          result[name] = [].concat(result[name]).concat(value)
          return
        } else {
          result[name] = value
        }
      })
      return result
    },
    listen : function(event, handler){
      var self = this
        , events = event.split(" ")
        , index = events.length
        , item
      while(index--){
        item = events[index]
        if(eventListener) self.addEventListener(item, handler)
        else self.attachEvent("on" + item, handler)
      }
      return self
    },
    stopListening : function(event, handler){
      var self = this
        , events = event.split(" ")
        , index = events.length
        , item
      if(!handler) return
      while(index--){
        item = events[index]
        if(eventListener) self.removeEventListener(item, handler)
        else self.detachEvent("on" + item, handler)
      }
      return self
    },
    getById : function(id){
      return $(id)
    },
    getByTag : function(tag){
      return toArray(this.getElementsByTagName(tag)).collect(function(item){ return $(item)})
    },
    getByClass : function(klass){
      if("getElementsByClassName" in document){
        return toArray(this.getElementsByClassName(klass)).collect(function(item){ return $(item)})
      } else {
        return toArray(this.getElementsByTagName("*")).collect(function(item){return $(item) }).select(function(item){return item.hasClass(klass)})
      }
    }
  }

  Element.extend(Element.methods)




  function Browser(){
    var self = this
      , userAgent = window.navigator.userAgent.toLowerCase()
      , className = []
  
    self.UA = userAgent
  
    ;("Webkit Firefox IE IE6 IE7 IE8 Opera Konqueror iPhone iPad iPod Android")
      .split(" ")
      .each(function(item){
        var _item = item.toLowerCase()
          , test = new RegExp(_item.replace(/[6-9]/, " $&")).test(userAgent)
  
        self["is" + item] = test
        if(test) className.push(_item) 
      })
  
    self.toClassName = function(){return className.join(" ")} 
  }
  
  extend(Craft, {
    Browser: new Browser()
  })


})(this, this.document)