/*!
 * iCheck v2.0.0 rc1, http://git.io/arlzeA
 * =======================================
 * Cross-platform checkboxes and radio buttons customization
 *
 * (c) Damir Sultanov - http://fronteed.com
 * MIT Licensed
 */

(function (win, doc, $) {

  // prevent multiple includes
  if (!win.ichecked) {
    win.ichecked = function () {
      $ = win.jQuery || win.Zepto;

      // default options
      var defaults = {

        // auto init on domready
        autoInit: true,

        // auto handle ajax loaded inputs
        autoAjax: false,

        // remove 300ms click delay on touch devices
        tap: true,

        // customization class names
        checkboxClass: 'icheckbox',
        radioClass: 'iradio',

        checkedClass: 'checked',
        disabledClass: 'disabled',
        indeterminateClass: 'indeterminate',

        hoverClass: 'hover',
        // focusClass: 'focus',
        // activeClass: 'active',

        // default callbacks
        callbacks: {
          ifCreated: false
        },

        // appended class names
        classes: {
          base: 'icheck',
          div: '#-item', // {base}-item
          area: '#-area-', // {base}-area-{value}
          input: '#-input', // {base}-input
          label: '#-label' // {base}-label
        }
      };

      // extend default options
      win.icheck = $.extend(defaults, win.icheck);

      // useragent sniffing
      var ua = win.navigator.userAgent;
      var ie = /MSIE [5-8]/.test(ua) || doc.documentMode < 9;
      var operaMini = /Opera Mini/.test(ua);

      // classes cache
      var baseClass = defaults.classes.base;
      var divClass = defaults.classes.div.replace('#', baseClass);
      var areaClass = defaults.classes.area.replace('#', baseClass);
      var nodeClass = defaults.classes.input.replace('#', baseClass);
      var labelClass = defaults.classes.label.replace('#', baseClass);

      // unset init classes
      delete defaults.classes;

      // default filter
      var filter = 'input[type=checkbox],input[type=radio]';

      // clickable areas container
      var areas = {};

      // hashes container
      var hashes = {};

      // hash recognizer
      var recognizer = new RegExp(baseClass + '\\[(.*?)\\]');

      // hash extractor
      var extract = function (className, matches, value) {
        if (!!className) {
          matches = recognizer.exec(className);

          if (matches && hashes[matches[1]]) {
            value = matches[1];
          }
        }

        return value;
      };

      // detect computed style support
      var computed = win.getComputedStyle;

      // detect pointer events support
      var isPointer = win.PointerEvent || win.MSPointerEvent;

      // detect touch events support
      var isTouch = 'ontouchend' in win;

      // detect mobile users
      var isMobile = /mobile|tablet|phone|ip(ad|od)|android|silk|webos/i.test(ua);

      // setup events
      var mouse = ['mouse', 'down', 'up', 'over', 'out']; // bubbling hover
      var pointer = win.PointerEvent ? ['pointer', mouse[1], mouse[2], mouse[3], mouse[4]] : ['MSPointer', 'Down', 'Up', 'Over', 'Out'];
      var touch = ['touch', 'start', 'end'];
      var noMouse = (isTouch && isMobile) || isPointer;

      // choose events
      var hoverStart = noMouse ? (isTouch ? touch[0] + touch[1] : pointer[0] + pointer[3]) : mouse[0] + mouse[3];
      var hoverEnd = noMouse ? (isTouch ? touch[0] + touch[2] : pointer[0] + pointer[4]) : mouse[0] + mouse[4];
      var tapStart = noMouse ? (isTouch ? false : pointer[0] + pointer[1]) : mouse[0] + mouse[1];
      var tapEnd = noMouse ? (isTouch ? false : pointer[0] + pointer[2]) : mouse[0] + mouse[2];
      var hover = !operaMini ? hoverStart + '.i ' + hoverEnd + '.i ' : '';
      var tap = !operaMini && tapStart ? tapStart + '.i ' + tapEnd + '.i' : '';

      // styles options
      var styleTag;
      var styleList;
      var styleArea = defaults.areaStyle !== false ? 'position:absolute;display:block;content:"";top:#;bottom:#;left:#;right:#;' : 0;
      var styleInput = 'position:absolute!;display:block!;outline:none!;' + (defaults.debug ? '' : 'opacity:0!;z-index:-99!;clip:rect(0 0 0 0)!;');

      // styles addition
      var style = function (rules, selector, area) {
        if (!styleTag) {

          // create container
          styleTag = doc.createElement('style');

          // append to header
          (doc.head || doc.getElementsByTagName('head')[0]).appendChild(styleTag);

          // webkit hack
          if (!win.createPopup) {
            styleTag.appendChild(doc.createTextNode(''));
          }

          styleList = styleTag.sheet || styleTag.styleSheet;
        }

        // choose selector
        if (!selector) {
          selector = 'div.' + (area ? areaClass + area + ':after' : divClass + ' input.' + nodeClass);
        }

        // replace shorthand rules
        rules = rules.replace(/!/g, ' !important');

        // append styles
        if (styleList.addRule) {
          styleList.addRule(selector, rules, 0);
        } else {
          styleList.insertRule(selector + '{' + rules + '}', 0);
        }
      };

      // append input's styles
      style(styleInput);

      // append styler's styles
      if ((isTouch && isMobile) || operaMini) {

        // force custor:pointer for mobile devices
        style('cursor:pointer!;', 'label.' + labelClass + ',div.' + divClass);
      }

      // append iframe's styles
      style('display:none!', 'iframe.icheck-frame'); // used to handle ajax-loaded inputs

      // class toggler
      var toggle = function (node, className, status, currentClass, updatedClass, addClass, removeClass) {
        currentClass = node.className;

        if (!!currentClass) {
          updatedClass = ' ' + currentClass + ' ';

          // add class
          if (status === 1) {
            addClass = className;

            // remove class
          } else if (status === 0) {
            removeClass = className;

            // add and remove class
          } else {
            addClass = className[0];
            removeClass = className[1];
          }

          // add class
          if (!!addClass && updatedClass.indexOf(' ' + addClass + ' ') < 0) {
            updatedClass += addClass + ' ';
          }

          // remove class
          if (!!removeClass && ~updatedClass.indexOf(' ' + removeClass + ' ')) {
            updatedClass = updatedClass.replace(' ' + removeClass + ' ', ' ');
          }

          // trim class
          updatedClass = updatedClass.replace(/^\s+|\s+$/g, '');

          // update class
          if (updatedClass !== currentClass) {
            node.className = updatedClass;
          }

          // return updated class
          return updatedClass;
        }
      };

      // traces remover
      var tidy = function (node, key, trigger, settings, className, parent) {
        if (hashes[key]) {
          settings = hashes[key];
          className = settings.className;
          parent = $(closest(node, 'div', className));

          // prevent overlapping
          if (parent.length) {

            // input
            $(node).removeClass(nodeClass + ' ' + className).attr('style', settings.style);

            // label
            $('label.' + settings.esc).removeClass(labelClass + ' ' + className);

            // parent
            $(parent).replaceWith($(node));

            // callback
            if (trigger) {
              callback(node, key, trigger);
            }
          }

          // unset current key
          hashes[key] = false;
        }
      };

      // nodes inspector
      var inspect = function (object, node, stack, direct, indirect) {
        stack = [];
        direct = object.length;

        // inspect object
        while (direct--) {
          node = object[direct];

          // direct input
          if (node.type) {

            // checkbox or radio button
            if (~filter.indexOf(node.type)) {
              stack.push(node);
            }

            // indirect input
          } else {
            node = $(node).find(filter);
            indirect = node.length;

            while (indirect--) {
              stack.push(node[indirect]);
            }
          }
        }

        return stack;
      };

      // parent searcher
      var closest = function (node, tag, className, parent) {
        while (node && node.nodeType !== 9) {
          node = node.parentNode;

          if (node && node.tagName == tag.toUpperCase() && ~node.className.indexOf(className)) {
            parent = node;
            break;
          }
        }

        return parent;
      };

      // callbacks farm
      var callback = function (node, key, name) {
        name = 'if' + name;

        // callbacks are allowed
        if (!!hashes[key].callbacks) {

          // indirect callback
          if (hashes[key].callbacks[name] !== false) {
            $(node).trigger(name);

            // direct callback
            if (typeof hashes[key].callbacks[name] == 'function') {
              hashes[key].callbacks[name](node, hashes[key]);
            }
          }
        }
      };

      // selection processor
      var process = function (data, options, ajax, silent) {

        // get inputs
        var elements = inspect(data);
        var element = elements.length;

        // loop through inputs
        while (element--) {
          var node = elements[element];
          var nodeAttr = node.attributes;
          var nodeAttrCache = {};
          var nodeAttrLength = nodeAttr.length;
          var nodeAttrName;
          var nodeAttrValue;
          var nodeData = {};
          var nodeDataCache = {}; // merged data
          var nodeDataProperty;
          var nodeId = node.id;
          var nodeInherit;
          var nodeInheritItem;
          var nodeInheritLength;
          var nodeString = node.className;
          var nodeStyle;
          var nodeType = node.type;
          var queryData = $.cache ? $.cache[node[$.expando]] : 0; // cached data
          var settings;
          var key = extract(nodeString);
          var keyClass;
          var handle;
          var styler;
          var stylerClass = '';
          var stylerStyle;
          var area = false;
          var label;
          var labelDirect;
          var labelIndirect;
          var labelKey;
          var labelString;
          var labels = [];
          var labelsLength;
          var fastClass = win.FastClick ? ' needsclick' : '';

          // parse options from HTML attributes
          while (nodeAttrLength--) {
            nodeAttrName = nodeAttr[nodeAttrLength].name;
            nodeAttrValue = nodeAttr[nodeAttrLength].value;

            if (~nodeAttrName.indexOf('data-')) {
              nodeData[nodeAttrName.substr(5)] = nodeAttrValue;
            }

            if (nodeAttrName == 'style') {
              nodeStyle = nodeAttrValue;
            }

            nodeAttrCache[nodeAttrName] = nodeAttrValue;
          }

          // parse options from jQuery or Zepto cache
          if (queryData && queryData.data) {
            nodeData = $.extend(nodeData, queryData.data);
          }

          // parse merged options
          for (nodeDataProperty in nodeData) {
            nodeAttrValue = nodeData[nodeDataProperty];

            if (nodeAttrValue == 'true' || nodeAttrValue == 'false') {
              nodeAttrValue = nodeAttrValue == 'true';
            }

            nodeDataCache[nodeDataProperty.replace(/checkbox|radio|class|id|label/g, function (string, position) {
              return position === 0 ? string : string.charAt(0).toUpperCase() + string.slice(1);
            })] = nodeAttrValue;
          }

          // merge options
          settings = $.extend({}, defaults, win.icheck, nodeDataCache, options);

          // input type filter
          handle = settings.handle;

          if (handle !== 'checkbox' && handle !== 'radio') {
            handle = filter;
          }

          // prevent unwanted init
          if (settings.init !== false && ~handle.indexOf(nodeType)) {

            // tidy before processing
            if (key) {
              tidy(node, key);
            }

            // generate random key
            while (!hashes[key]) {
              key = Math.random().toString(36).substr(2, 5); // 5 symbols

              if (!hashes[key]) {
                keyClass = baseClass + '[' + key + ']';
                break;
              }
            }

            // prevent unwanted duplicates
            delete settings.autoInit;
            delete settings.autoAjax;

            // save settings
            settings.style = nodeStyle || '';
            settings.className = keyClass;
            settings.esc = keyClass.replace(/(\[|\])/g, '\\$1');
            hashes[key] = settings;

            // find direct label
            labelDirect = closest(node, 'label', '');

            if (labelDirect) {

              // normalize "for" attribute
              if (!!!labelDirect.htmlFor && !!nodeId) {
                labelDirect.htmlFor = nodeId;
              }

              labels.push(labelDirect);
            }

            // find indirect label
            if (!!nodeId) {
              labelIndirect = $('label[for="' + nodeId + '"]');

              // merge labels
              while (labelIndirect.length--) {
                label = labelIndirect[labelIndirect.length];

                if (label !== labelDirect) {
                  labels.push(label);
                }
              }
            }

            // loop through labels
            labelsLength = labels.length;

            while (labelsLength--) {
              label = labels[labelsLength];
              labelString = label.className;
              labelKey = extract(labelString);

              // remove previous key
              if (labelKey) {
                labelString = toggle(label, baseClass + '[' + labelKey + ']', 0);
              } else {
                labelString = (!!labelString ? labelString + ' ' : '') + labelClass;
              }

              // update label's class
              label.className = labelString + ' ' + keyClass + fastClass;
            }

            // prepare styler
            styler = doc.createElement('div');

            // parse inherited options
            if (!!settings.inherit) {
              nodeInherit = settings.inherit.split(/\s*,\s*/);
              nodeInheritLength = nodeInherit.length;

              while (nodeInheritLength--) {
                nodeInheritItem = nodeInherit[nodeInheritLength];

                if (nodeAttrCache[nodeInheritItem] !== undefined) {
                  if (nodeInheritItem == 'class') {
                    stylerClass += nodeAttrCache[nodeInheritItem] + ' ';
                  } else {
                    styler.setAttribute(nodeInheritItem, nodeInheritItem == 'id' ? baseClass + '-' + nodeAttrCache[nodeInheritItem] : nodeAttrCache[nodeInheritItem]);
                  }
                }
              }
            }

            // set input's type class
            stylerClass += settings[nodeType + 'Class'];

            // set styler's key
            stylerClass += ' ' + divClass + ' ' + keyClass;

            // append area styles
            if (settings.area && styleArea) {
              area = ('' + settings.area).replace(/%|px|em|\+|-/g, '') | 0;

              if (area) {

                // append area's styles
                if (!areas[area]) {
                  style(styleArea.replace(/#/g, '-' + area + '%'), false, area);
                  areas[area] = true;
                }

                stylerClass += ' ' + areaClass + area;
              }
            }

            // update styler's class
            styler.className = stylerClass + fastClass;

            // update node's class
            node.className = (!!nodeString ? nodeString + ' ' : '') + nodeClass + ' ' + keyClass;

            // replace node
            node.parentNode.replaceChild(styler, node);

            // append node
            styler.appendChild(node);

            // append additions
            if (!!settings.insert) {
              $(styler).append(settings.insert);
            }

            // set relative position
            if (area) {

              // get styler's position
              if (computed) {
                stylerStyle = computed(styler, null).getPropertyValue('position');
              } else {
                stylerStyle = styler.currentStyle.position;
              }

              // update styler's position
              if (stylerStyle == 'static') {
                styler.style.position = 'relative';
              }
            }

            // operate
            operate(node, styler, key, 'updated', true, false, ajax);
            hashes[key].done = true;

            // ifCreated callback
            if (!silent) {
              callback(node, key, 'Created');
            }
          }
        }
      };

      // operations center
      var operate = function (node, parent, key, method, silent, before, ajax) {
        var settings = hashes[key];
        var states = {};
        var changes = {};

        // current states
        states.checked = [node.checked, 'Checked', 'Unchecked'];

        if ((!before || ajax) && method !== 'click') {
          states.disabled = [node.disabled, 'Disabled', 'Enabled'];
          states.indeterminate = [node.getAttribute('indeterminate') == 'true' || !!node.indeterminate, 'Indeterminate', 'Determinate'];
        }

        // methods
        if (method == 'updated' || method == 'click') {
          changes.checked = before ? !states.checked[0] : states.checked[0];

          if ((!before || ajax) && method !== 'click') {
            changes.disabled = states.disabled[0];
            changes.indeterminate = states.indeterminate[0];
          }

        } else if (method == 'checked' || method == 'unchecked') {
          changes.checked = method == 'checked';

        } else if (method == 'disabled' || method == 'enabled') {
          changes.disabled = method == 'disabled';

        } else if (method == 'indeterminate' || method == 'determinate') {
          changes.indeterminate = method !== 'determinate';

          // "toggle" method
        } else {
          changes.checked = !states.checked[0];
        }

        // apply changes
        change(node, parent, states, changes, key, settings, method, silent, before, ajax);
      };

      // state changer
      var change = function (node, parent, states, changes, key, settings, method, silent, before, ajax, loop) {
        var type = node.type;
        var typeCapital = type == 'radio' ? 'Radio' : 'Checkbox';
        var property;
        var value;
        var classes;
        var inputClass;
        var label;
        var labelClass = 'LabelClass';
        var form;
        var radios;
        var radiosLength;
        var radio;
        var radioKey;
        var radioStates;
        var radioChanges;
        var changed;
        var toggled;

        // check parent
        if (!parent) {
          parent = closest(node, 'div', settings.className);
        }

        // continue if parent exists
        if (parent) {

          // detect changes
          for (property in changes) {
            value = changes[property];

            // update node's property
            if (states[property][0] !== value && method !== 'updated' && method !== 'click') {
              node[property] = value;
            }

            // update ajax attributes
            if (ajax) {
              if (value) {
                node.setAttribute(property, property);
              } else {
                node.removeAttribute(property);
              }
            }

            // update key's property
            if (settings[property] !== value) {
              settings[property] = value;
              changed = true;

              if (property == 'checked') {
                toggled = true;

                // find assigned radios
                if (!loop && value && (!!hashes[key].done || ajax) && type == 'radio' && !!node.name) {
                  form = closest(node, 'form', '');
                  radios = 'input[name="' + node.name + '"]';
                  radios = form && !ajax ? $(form).find(radios) : $(radios);
                  radiosLength = radios.length;

                  while (radiosLength--) {
                    radio = radios[radiosLength];
                    radioKey = extract(radio.className);

                    // toggle radios
                    if (node !== radio && hashes[radioKey] && hashes[radioKey].checked) {
                      radioStates = { checked: [true, 'Checked', 'Unchecked'] };
                      radioChanges = { checked: false };

                      change(radio, false, radioStates, radioChanges, radioKey, hashes[radioKey], 'updated', silent, before, ajax, true);
                    }
                  }
                }
              }

              // cache classes
              classes = [
                settings[property + 'Class'], // 0, example: checkedClass
                settings[property + typeCapital + 'Class'], // 1, example: checkedCheckboxClass
                settings[states[property][1] + 'Class'], // 2, example: uncheckedClass
                settings[states[property][1] + typeCapital + 'Class'], // 3, example: uncheckedCheckboxClass
                settings[property + labelClass] // 4, example: checkedLabelClass
              ];

              // value == false
              inputClass = [classes[3] || classes[2], classes[1] || classes[0]];

              // value == true
              if (value) {
                inputClass.reverse();
              }

              // update parent's class
              toggle(parent, inputClass);

              // update labels's class
              if (!!settings.mirror && !!classes[4]) {
                label = $('label.' + settings.esc);

                while (label.length--) {
                  toggle(label[label.length], classes[4], value ? 1 : 0);
                }
              }

              // callback
              if (!silent || loop) {
                callback(node, key, states[property][value ? 1 : 2]); // ifChecked or ifUnchecked
              }
            }
          }

          // additional callbacks
          if (!silent || loop) {
            if (changed) {
              callback(node, key, 'Changed'); // ifChanged
            }

            if (toggled) {
              callback(node, key, 'Toggled'); // ifToggled
            }
          }

          // cursor addition
          if (!!settings.cursor && !isMobile) {

            // 'pointer' for enabled
            if (!settings.disabled && !settings.pointer) {
              parent.style.cursor = 'pointer';
              settings.pointer = true;

              // 'default' for disabled
            } else if (settings.disabled && settings.pointer) {
              parent.style.cursor = 'default';
              settings.pointer = false;
            }
          }

          // update settings
          hashes[key] = settings;
        }
      };

      // plugin definition
      $.fn.icheck = function (options, fire) {

        // detect methods
        if (/^(checked|unchecked|indeterminate|determinate|disabled|enabled|updated|toggle|destroy|data|styler)$/.test(options)) {
          var items = inspect(this);
          var itemsLength = items.length;

          // loop through inputs
          while (itemsLength--) {
            var item = items[itemsLength];
            var key = extract(item.className);

            if (key) {

              // 'data' method
              if (options == 'data') {
                return hashes[key];

                // 'styler' method
              } else if (options == 'styler') {
                return closest(item, 'div', hashes[key].className);

              } else {
                if (options == 'destroy') {
                  tidy(item, key, 'Destroyed');
                } else {
                  operate(item, false, key, options);
                }

                // callback
                if (typeof fire == 'function') {
                  fire(item);
                }
              }
            }
          }

          // basic setup
        } else if (typeof options == 'object' || !options) {
          process(this, options || {});
        }

        // chain
        return this;
      };

      // cached last key
      var lastKey;

      // bind label and styler
      $(doc).on('click.i ' + hover + tap, 'label.' + labelClass + ',div.' + divClass, function (event) {
        var self = this;
        var key = extract(self.className);

        if (key) {
          var emitter = event.type;
          var settings = hashes[key];
          var className = settings.esc; // escaped class name
          var div = self.tagName == 'DIV';
          var input;
          var target;
          var partner;
          var activate;
          var states = [
            ['label', settings.activeLabelClass, settings.hoverLabelClass],
            ['div', settings.activeClass, settings.hoverClass]
          ];

          // reverse array
          if (div) {
            states.reverse();
          }

          // active state
          if (emitter == tapStart || emitter == tapEnd) {

            // toggle self's active class
            if (!!states[0][1]) {
              toggle(self, states[0][1], emitter == tapStart ? 1 : 0);
            }

            // toggle partner's active class
            if (!!settings.mirror && !!states[1][1]) {
              partner = $(states[1][0] + '.' + className);

              while (partner.length--) {
                toggle(partner[partner.length], states[1][1], emitter == tapStart ? 1 : 0);
              }
            }

            // fast click
            if (div && emitter == tapEnd && !!settings.tap && isMobile && isPointer && !operaMini) {
              activate = true;
            }

            // hover state
          } else if (emitter == hoverStart || emitter == hoverEnd) {

            // toggle self's hover class
            if (!!states[0][2]) {
              toggle(self, states[0][2], emitter == hoverStart ? 1 : 0);
            }

            // toggle partner's hover class
            if (!!settings.mirror && !!states[1][2]) {
              partner = $(states[1][0] + '.' + className);

              while (partner.length--) {
                toggle(partner[partner.length], states[1][2], emitter == hoverStart ? 1 : 0);
              }
            }

            // fast click
            if (div && emitter == hoverEnd && !!settings.tap && isMobile && isTouch && !operaMini) {
              activate = true;
            }

            // click
          } else if (div) {
            if (!(isMobile && (isTouch || isPointer)) || !!!settings.tap || operaMini) {
              activate = true;
            }
          }

          // trigger input's click
          if (activate) {

            // currentTarget hack
            setTimeout(function () {
              target = event.currentTarget || {};

              if (target.tagName !== 'LABEL') {
                if (!settings.change || (+new Date() - settings.change > 100)) {
                  input = $(self).find('input.' + className).click();

                  if (ie || operaMini) {
                    input.change();
                  }
                }
              }
            }, 2);
          }
        }

        // bind input
      }).on('click.i change.i focusin.i focusout.i keyup.i keydown.i', 'input.' + nodeClass, function (event) {
        var self = this;
        var key = extract(self.className);

        if (key) {
          var emitter = event.type;
          var settings = hashes[key];
          var className = settings.esc; // escaped class name
          var parent = emitter == 'click' ? false : closest(self, 'div', settings.className);
          var label;
          var states;

          // click
          if (emitter == 'click') {
            hashes[key].change = +new Date();

            // prevent event bubbling to parent
            event.stopPropagation();

            // change
          } else if (emitter == 'change') {

            if (parent && !self.disabled) {
              operate(self, parent, key, 'click'); // 'click' method
            }

            // focus state
          } else if (~emitter.indexOf('focus')) {
            states = [settings.focusClass, settings.focusLabelClass];

            // toggle parent's focus class
            if (!!states[0] && parent) {
              toggle(parent, states[0], emitter == 'focusin' ? 1 : 0);
            }

            // toggle label's focus class
            if (!!settings.mirror && !!states[1]) {
              label = $('label.' + className);

              while (label.length--) {
                toggle(label[label.length], states[1], emitter == 'focusin' ? 1 : 0);
              }
            }

            // keyup or keydown (event fired before state is changed, except Opera 9-12)
          } else if (parent && !self.disabled) {

            // keyup
            if (emitter == 'keyup') {

              // spacebar or arrow
              if (self.type == 'checkbox' && event.keyCode == 32 && settings.keydown || self.type == 'radio' && !self.checked) {
                operate(self, parent, key, 'click', false, true); // 'toggle' method
              }

              hashes[key].keydown = false;
              hashes[lastKey] && (hashes[lastKey].keydown = false);

              // keydown
            } else {
              lastKey = key;
              hashes[key].keydown = true;
            }
          }
        }

        // domready
      }).ready(function () {

        // auto init
        if (win.icheck.autoInit) {
          $('.' + baseClass).icheck();
        }

        // auto ajax
        if (win.jQuery) {

          // body selector cache
          var body = doc.body || doc.getElementsByTagName('body')[0];

          // apply converter
          $.ajaxSetup({
            converters: {
              'text html': function (data) {
                if (win.icheck.autoAjax && body) {
                  var frame = doc.createElement('iframe'); // create container
                  var frameData;

                  // set attributes
                  if (!ie) {
                    frame.style = 'display:none';
                  }

                  frame.className = 'iframe.icheck-frame';
                  frame.src = 'about:blank';

                  // append container to document
                  body.appendChild(frame);

                  // save container's content
                  frameData = frame.contentDocument ? frame.contentDocument : frame.contentWindow.document;

                  // append data to content
                  frameData.open();
                  frameData.write(data);
                  frameData.close();

                  // remove container from document
                  body.removeChild(frame);

                  // setup object
                  frameData = $(frameData);

                  // customize inputs
                  process(frameData.find('.' + baseClass), {}, true);

                  // extract HTML
                  frameData = frameData[0];
                  data = (frameData.body || frameData.getElementsByTagName('body')[0]).innerHTML;
                  frameData = null; // prevent memory leaks
                }

                return data;
              }
            }
          });
        }
      });
    };

    // expose iCheck as an AMD module
    if (typeof define == 'function' && define.amd) {
      define('icheck', [win.jQuery ? 'jquery' : 'zepto'], win.ichecked);
    } else {
      win.ichecked();
    }
  }
}(window, document));
