text: /**
   * skylarkjs - An Elegant JavaScript Library and HTML5 Application Framework.
   * @author Hudaokeji Co.,Ltd
   * @version v0.9.8-beta
   * @link www.skylarkjs.org
   * @license MIT
   */
  (function(factory,globals) {
    var define = globals.define,
        require = globals.require,
        isAmd = (typeof define === 'function' && define.amd),
        isCmd = (!isAmd && typeof exports !== 'undefined');
  
    if (!isAmd && !define) {
      var map = {};
      function absolute(relative, base) {
          if (relative[0]!==".") {
            return relative;
          }
          var stack = base.split("/"),
              parts = relative.split("/");
          stack.pop();
          for (var i=0; i<parts.length; i++) {
              if (parts[i] == ".")
                  continue;
              if (parts[i] == "..")
                  stack.pop();
              else
                  stack.push(parts[i]);
          }
          return stack.join("/");
      }
      define = globals.define = function(id, deps, factory) {
          if (typeof factory == 'function') {
              map[id] = {
                  factory: factory,
                  deps: deps.map(function(dep){
                    return absolute(dep,id);
                  }),
                  exports: null
              };
              require(id);
          } else {
              map[id] = factory;
          }
      };
      require = globals.require = function(deps,cb) {
          function requireOne(id) {
              if (!map.hasOwnProperty(id)) {
                  throw new Error('Module ' + id + ' has not been defined');
              }
              var module = map[id];
              if (!module.exports) {
                  var args = [];
  
                  module.deps.forEach(function(dep){
                      args.push(require(dep));
                  })
  
                  module.exports = module.factory.apply(window, args);
              }
              return module.exports;
          }
          var onedep = typeof deps === "string";
          if (!cb && onedep) {
              return requireOne(deps);
          }
          if (onedep) {
              deps = [deps];
          }
          var modules = deps.map(function(id){
              return requireOne(id);
          });
          if (cb) {
              cb.apply(null,modules);
          } else {
              return modules;
          }
  
      };
    }
  
    factory(define,require);
  
    function xhrGet(url,callback) {
      var xhr = new XMLHttpRequest();
      xhr.onreadystatechange = function()   {
          if (this.readyState == 4) {
              callback(this.response || this.responseText);
          }
      }
      xhr.open("GET",url,true);
      xhr.send( null );
    }
    if (!isAmd) {
      var skylarkjs = require("skylarkjs");
  
      if (isCmd) {
        exports = skylarkjs;
      } else {
        globals.skylarkjs = skylarkjs;
      }
    } else {
      require.config({
          baseUrl : "./"
      });
    }
  
  require([
    "skylarkjs"
  ], function (skylark,http) {
      xhrGet("./slax-config.json",function(res){
          if (!res) {
              console.error("can't find the slax-config.json!");
              return;
          }
          var cfg = JSON.parse(res);
          if (isAmd) {
              require.config(cfg.runtime);
          }
  
         
          var initApp = function(spa, _cfg) {
              _cfg = _cfg || cfg;
              if (cfg.contextPath) {
                _cfg.baseUrl = cfg.contextPath;
              }
              var app = spa(_cfg);
  
              globals.go =  function(path, force) {
                  app.go(path, force);
              };
  
              app.prepare().then(function(){
                  app.run();
              });
          };
          if(cfg.spaModule) {
              require([cfg.spaModule], function(spa) {
                  if(spa._start) {
                      spa._start().then(function(_cfg){
                          initApp(spa, _cfg);
                      });
                  } else {
                      initApp(spa);
                  }
              });
          } else {
              initApp(skylark.spa);
          }
      });
  
  
  });
  
  })(function(define,require) {
  define('skylark-langx/skylark',[], function() {
      var skylark = {
  
      };
      return skylark;
  });
  
  define('skylark-utils/skylark',["skylark-langx/skylark"], function(skylark) {
      return skylark;
  });
  
  define('skylarkjs/skylark',[
      "skylark-utils/skylark"
  ], function(skylark) {
      return skylark;
  });
  
  define('skylark-langx/types',[
  ],function(){
      var type = (function() {
          var class2type = {};
  
          // Populate the class2type map
          "Boolean Number String Function Array Date RegExp Object Error".split(" ").forEach(function(name) {
              class2type["[object " + name + "]"] = name.toLowerCase();
          });
  
          return function type(obj) {
              return obj == null ? String(obj) :
                  class2type[toString.call(obj)] || "object";
          };
      })();
  
      function isArray(object) {
          return object && object.constructor === Array;
      }
  
      function isArrayLike(obj) {
          return !isString(obj) && !isHtmlNode(obj) && typeof obj.length == 'number' && !isFunction(obj);
      }
  
      function isBoolean(obj) {
          return typeof(obj) === "boolean";
      }
  
      function isDefined(obj) {
          return typeof obj !== 'undefined';
      }
  
      function isDocument(obj) {
          return obj != null && obj.nodeType == obj.DOCUMENT_NODE;
      }
  
      function isEmptyObject(obj) {
          var name;
          for (name in obj) {
              if (obj[name] !== null) {
                  return false;
              }
          }
          return true;
      }
  
      function isFunction(value) {
          return type(value) == "function";
      }
  
      function isHtmlNode(obj) {
          return obj && (obj instanceof Node);
      }
  
      function isInstanceOf( /*Object*/ value, /*Type*/ type) {
          //Tests whether the value is an instance of a type.
          if (value === undefined) {
              return false;
          } else if (value === null || type == Object) {
              return true;
          } else if (typeof value === "number") {
              return type === Number;
          } else if (typeof value === "string") {
              return type === String;
          } else if (typeof value === "boolean") {
              return type === Boolean;
          } else if (typeof value === "string") {
              return type === String;
          } else {
              return (value instanceof type) || (value && value.isInstanceOf ? value.isInstanceOf(type) : false);
          }
      }
  
      function isNumber(obj) {
          return typeof obj == 'number';
      }
  
      function isObject(obj) {
          return type(obj) == "object";
      }
  
      function isPlainObject(obj) {
          return isObject(obj) && !isWindow(obj) && Object.getPrototypeOf(obj) == Object.prototype;
      }
  
      function isString(obj) {
          return typeof obj === 'string';
      }
  
      function isWindow(obj) {
          return obj && obj == obj.window;
      }
  
      function isSameOrigin(href) {
          if (href) {
              var origin = location.protocol + '//' + location.hostname;
              if (location.port) {
                  origin += ':' + location.port;
              }
              return href.startsWith(origin);
          }
      }
  
      return {
  
          isArray: isArray,
  
          isArrayLike: isArrayLike,
  
          isBoolean: isBoolean,
  
          isDefined: isDefined,
  
          isDocument: isDocument,
  
          isEmptyObject: isEmptyObject,
  
          isFunction: isFunction,
  
          isHtmlNode: isHtmlNode,
  
          isNumber: isNumber,
  
          isObject: isObject,
  
          isPlainObject: isPlainObject,
  
          isString: isString,
  
          isSameOrigin: isSameOrigin,
  
          isWindow: isWindow,
  
          type: type
      };
  
  });
  define('skylark-langx/arrays',[
  	"./types"
  ],function(types){
  	var filter = Array.prototype.filter,
  		isArrayLike = types.isArrayLike;
  
      function compact(array) {
          return filter.call(array, function(item) {
              return item != null;
          });
      }
  
      function each(obj, callback) {
          var length, key, i, undef, value;
  
          if (obj) {
              length = obj.length;
  
              if (length === undef) {
                  // Loop object items
                  for (key in obj) {
                      if (obj.hasOwnProperty(key)) {
                          value = obj[key];
                          if (callback.call(value, key, value) === false) {
                              break;
                          }
                      }
                  }
              } else {
                  // Loop array items
                  for (i = 0; i < length; i++) {
                      value = obj[i];
                      if (callback.call(value, i, value) === false) {
                          break;
                      }
                  }
              }
          }
  
          return this;
      }
  
      function flatten(array) {
          if (isArrayLike(array)) {
              var result = [];
              for (var i = 0; i < array.length; i++) {
                  var item = array[i];
                  if (isArrayLike(item)) {
                      for (var j = 0; j < item.length; j++) {
                          result.push(item[j]);
                      }
                  } else {
                      result.push(item);
                  }
              }
              return result;
          } else {
              return array;
          }
          //return array.length > 0 ? concat.apply([], array) : array;
      }
  
      function grep(array, callback) {
          var out = [];
  
          each(array, function(i, item) {
              if (callback(item, i)) {
                  out.push(item);
              }
          });
  
          return out;
      }
  
      function inArray(item, array) {
          if (!array) {
              return -1;
          }
          var i;
  
          if (array.indexOf) {
              return array.indexOf(item);
          }
  
          i = array.length;
          while (i--) {
              if (array[i] === item) {
                  return i;
              }
          }
  
          return -1;
      }
  
      function makeArray(obj, offset, startWith) {
         if (isArrayLike(obj) ) {
          return (startWith || []).concat(Array.prototype.slice.call(obj, offset || 0));
        }
  
        // array of single index
        return [ obj ];             
      }
  
      function map(elements, callback) {
          var value, values = [],
              i, key
          if (isArrayLike(elements))
              for (i = 0; i < elements.length; i++) {
                  value = callback.call(elements[i], elements[i], i);
                  if (value != null) values.push(value)
              }
          else
              for (key in elements) {
                  value = callback.call(elements[key], elements[key], key);
                  if (value != null) values.push(value)
              }
          return flatten(values)
      }
  
      function uniq(array) {
          return filter.call(array, function(item, idx) {
              return array.indexOf(item) == idx;
          })
      }
  
      return {
          compact: compact,
  
          first : function(items,n) {
              if (n) {
                  return items.slice(0,n);
              } else {
                  return items[0];
              }
          },
  
  	    each: each,
  
          flatten: flatten,
  
          inArray: inArray,
  
          makeArray: makeArray,
  
          map : map,
          
          uniq : uniq
  
      }
  });
  define('skylark-langx/objects',[
  	"./types"
  ],function(types){
  	var hasOwnProperty = Object.prototype.hasOwnProperty,
          slice = Array.prototype.slice,
          isBoolean = types.isBoolean,
          isFunction = types.isFunction,
  		isObject = types.isObject,
  		isPlainObject = types.isPlainObject,
  		isArray = types.isArray;
  
       // An internal function for creating assigner functions.
      function createAssigner(keysFunc, defaults) {
          return function(obj) {
            var length = arguments.length;
            if (defaults) obj = Object(obj);  
            if (length < 2 || obj == null) return obj;
            for (var index = 1; index < length; index++) {
              var source = arguments[index],
                  keys = keysFunc(source),
                  l = keys.length;
              for (var i = 0; i < l; i++) {
                var key = keys[i];
                if (!defaults || obj[key] === void 0) obj[key] = source[key];
              }
            }
            return obj;
         };
      }
  
      // Internal recursive comparison function for `isEqual`.
      var eq, deepEq;
      var SymbolProto = typeof Symbol !== 'undefined' ? Symbol.prototype : null;
  
      eq = function(a, b, aStack, bStack) {
          // Identical objects are equal. `0 === -0`, but they aren't identical.
          // See the [Harmony `egal` proposal](http://wiki.ecmascript.org/doku.php?id=harmony:egal).
          if (a === b) return a !== 0 || 1 / a === 1 / b;
          // `null` or `undefined` only equal to itself (strict comparison).
          if (a == null || b == null) return false;
          // `NaN`s are equivalent, but non-reflexive.
          if (a !== a) return b !== b;
          // Exhaust primitive checks
          var type = typeof a;
          if (type !== 'function' && type !== 'object' && typeof b != 'object') return false;
          return deepEq(a, b, aStack, bStack);
      };
  
      // Internal recursive comparison function for `isEqual`.
      deepEq = function(a, b, aStack, bStack) {
          // Unwrap any wrapped objects.
          //if (a instanceof _) a = a._wrapped;
          //if (b instanceof _) b = b._wrapped;
          // Compare `[[Class]]` names.
          var className = toString.call(a);
          if (className !== toString.call(b)) return false;
          switch (className) {
              // Strings, numbers, regular expressions, dates, and booleans are compared by value.
              case '[object RegExp]':
              // RegExps are coerced to strings for comparison (Note: '' + /a/i === '/a/i')
              case '[object String]':
                  // Primitives and their corresponding object wrappers are equivalent; thus, `"5"` is
                  // equivalent to `new String("5")`.
                  return '' + a === '' + b;
              case '[object Number]':
                  // `NaN`s are equivalent, but non-reflexive.
                  // Object(NaN) is equivalent to NaN.
                  if (+a !== +a) return +b !== +b;
                  // An `egal` comparison is performed for other numeric values.
                  return +a === 0 ? 1 / +a === 1 / b : +a === +b;
              case '[object Date]':
              case '[object Boolean]':
                  // Coerce dates and booleans to numeric primitive values. Dates are compared by their
                  // millisecond representations. Note that invalid dates with millisecond representations
                  // of `NaN` are not equivalent.
                  return +a === +b;
              case '[object Symbol]':
                  return SymbolProto.valueOf.call(a) === SymbolProto.valueOf.call(b);
          }
  
          var areArrays = className === '[object Array]';
          if (!areArrays) {
              if (typeof a != 'object' || typeof b != 'object') return false;
              // Objects with different constructors are not equivalent, but `Object`s or `Array`s
              // from different frames are.
              var aCtor = a.constructor, bCtor = b.constructor;
              if (aCtor !== bCtor && !(isFunction(aCtor) && aCtor instanceof aCtor &&
                                 isFunction(bCtor) && bCtor instanceof bCtor)
                            && ('constructor' in a && 'constructor' in b)) {
                  return false;
              }
          }
          // Assume equality for cyclic structures. The algorithm for detecting cyclic
          // structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`.
  
          // Initializing stack of traversed objects.
          // It's done here since we only need them for objects and arrays comparison.
          aStack = aStack || [];
          bStack = bStack || [];
          var length = aStack.length;
          while (length--) {
              // Linear search. Performance is inversely proportional to the number of
              // unique nested structures.
              if (aStack[length] === a) return bStack[length] === b;
          }
  
          // Add the first object to the stack of traversed objects.
          aStack.push(a);
          bStack.push(b);
  
          // Recursively compare objects and arrays.
          if (areArrays) {
              // Compare array lengths to determine if a deep comparison is necessary.
              length = a.length;
              if (length !== b.length) return false;
              // Deep compare the contents, ignoring non-numeric properties.
              while (length--) {
                  if (!eq(a[length], b[length], aStack, bStack)) return false;
              }
          } else {
              // Deep compare objects.
              var keys = Object.keys(a), key;
              length = keys.length;
              // Ensure that both objects contain the same number of properties before comparing deep equality.
              if (Object.keys(b).length !== length) return false;
              while (length--) {
                  // Deep compare each member
                  key = keys[length];
                  if (!(b[key]!==undefined && eq(a[key], b[key], aStack, bStack))) return false;
              }
          }
          // Remove the first object from the stack of traversed objects.
          aStack.pop();
          bStack.pop();
          return true;
      };
  
      // Retrieve all the property names of an object.
      function allKeys(obj) {
          if (!isObject(obj)) return [];
          var keys = [];
          for (var key in obj) keys.push(key);
          return keys;
      }
  
      // Retrieve the names of an object's own properties.
      // Delegates to **ECMAScript 5**'s native `Object.keys`.
      function keys(obj) {
          if (isObject(obj)) return [];
          var keys = [];
          for (var key in obj) if (has(obj, key)) keys.push(key);
          return keys;
      }
  
      function has(obj, path) {
          if (!isArray(path)) {
              return obj != null && hasOwnProperty.call(obj, path);
          }
          var length = path.length;
          for (var i = 0; i < length; i++) {
              var key = path[i];
              if (obj == null || !hasOwnProperty.call(obj, key)) {
                  return false;
              }
              obj = obj[key];
          }
          return !!length;
      }
  
     // Perform a deep comparison to check if two objects are equal.
      function isEqual(a, b) {
          return eq(a, b);
      }
  
      // Returns whether an object has a given set of `key:value` pairs.
      function isMatch(object, attrs) {
          var keys = keys(attrs), length = keys.length;
          if (object == null) return !length;
          var obj = Object(object);
          for (var i = 0; i < length; i++) {
            var key = keys[i];
            if (attrs[key] !== obj[key] || !(key in obj)) return false;
          }
          return true;
      }    
  
      function _mixin(target, source, deep, safe) {
          for (var key in source) {
              //if (!source.hasOwnProperty(key)) {
              //    continue;
              //}
              if (safe && target[key] !== undefined) {
                  continue;
              }
              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] = [];
                  }
                  _mixin(target[key], source[key], deep, safe);
              } else if (source[key] !== undefined) {
                  target[key] = source[key]
              }
          }
          return target;
      }
  
      function _parseMixinArgs(args) {
          var params = slice.call(arguments, 0),
              target = params.shift(),
              deep = false;
          if (isBoolean(params[params.length - 1])) {
              deep = params.pop();
          }
  
          return {
              target: target,
              sources: params,
              deep: deep
          };
      }
  
      function mixin() {
          var args = _parseMixinArgs.apply(this, arguments);
  
          args.sources.forEach(function(source) {
              _mixin(args.target, source, args.deep, false);
          });
          return args.target;
      }
  
      function removeItem(items, item) {
          if (isArray(items)) {
              var idx = items.indexOf(item);
              if (idx != -1) {
                  items.splice(idx, 1);
              }
          } else if (isPlainObject(items)) {
              for (var key in items) {
                  if (items[key] == item) {
                      delete items[key];
                      break;
                  }
              }
          }
  
          return this;
      }
  
      function result(obj, path, fallback) {
          if (!isArray(path)) {
              path = [path]
          };
          var length = path.length;
          if (!length) {
            return isFunction(fallback) ? fallback.call(obj) : fallback;
          }
          for (var i = 0; i < length; i++) {
            var prop = obj == null ? void 0 : obj[path[i]];
            if (prop === void 0) {
              prop = fallback;
              i = length; // Ensure we don't continue iterating.
            }
            obj = isFunction(prop) ? prop.call(obj) : prop;
          }
  
          return obj;
      }
  
      function safeMixin() {
          var args = _parseMixinArgs.apply(this, arguments);
  
          args.sources.forEach(function(source) {
              _mixin(args.target, source, args.deep, true);
          });
          return args.target;
      }
  
      // Retrieve the values of an object's properties.
      function values(obj) {
          var keys = _.keys(obj);
          var length = keys.length;
          var values = Array(length);
          for (var i = 0; i < length; i++) {
              values[i] = obj[keys[i]];
          }
          return values;
      }
  
  
      
      function clone( /*anything*/ src,checkCloneMethod) {
          var copy;
          if (src === undefined || src === null) {
              copy = src;
          } else if (checkCloneMethod && src.clone) {
              copy = src.clone();
          } else if (isArray(src)) {
              copy = [];
              for (var i = 0; i < src.length; i++) {
                  copy.push(clone(src[i]));
              }
          } else if (isPlainObject(src)) {
              copy = {};
              for (var key in src) {
                  copy[key] = clone(src[key]);
              }
          } else {
              copy = src;
          }
  
          return copy;
  
      }
  
      return {
          allKeys: allKeys,
  
          clone: clone,
  
          defaults : createAssigner(allKeys, true),
  
          has: has,
  
          isEqual: isEqual,
  
          isMatch: isMatch,
  
          keys: keys,
  
          mixin: mixin,
  
          removeItem: removeItem,
  
          result : result,
          
          safeMixin: safeMixin,
  
          values: values
      };
  
  });
  define('skylark-langx/klass',[
      "./arrays",
      "./objects",
      "./types"
  ],function(arrays,objects,types){
      var uniq = arrays.uniq,
          has = objects.has,
          mixin = objects.mixin,
          isArray = types.isArray,
          isDefined = types.isDefined;
      
      function inherit(ctor, base) {
          var f = function() {};
          f.prototype = base.prototype;
  
          ctor.prototype = new f();
      }
  
  
      var f1 = function() {
          function extendClass(ctor, props, options) {
              // Copy the properties to the prototype of the class.
              var proto = ctor.prototype,
                  _super = ctor.superclass.prototype,
                  noOverrided = options && options.noOverrided;
  
              for (var name in props) {
                  if (name === "constructor") {
                      continue;
                  }
  
                  // Check if we're overwriting an existing function
                  var prop = props[name];
                  if (typeof props[name] == "function") {
                      proto[name] =  !prop._constructor && !noOverrided && typeof _super[name] == "function" ?
                            (function(name, fn, superFn) {
                              return function() {
                                  var tmp = this.overrided;
  
                                  // Add a new ._super() method that is the same method
                                  // but on the super-class
                                  this.overrided = superFn;
  
                                  // The method only need to be bound temporarily, so we
                                  // remove it when we're done executing
                                  var ret = fn.apply(this, arguments);
  
                                  this.overrided = tmp;
  
                                  return ret;
                              };
                          })(name, prop, _super[name]) :
                          prop;
                  } else if (typeof prop == "object" && prop!==null && (prop.get)) {
                      Object.defineProperty(proto,name,prop);
                  } else {
                      proto[name] = prop;
                  }
              }
              return ctor;
          }
  
          function serialMixins(ctor,mixins) {
              var result = [];
  
              mixins.forEach(function(mixin){
                  if (has(mixin,"__mixins__")) {
                       throw new Error("nested mixins");
                  }
                  var clss = [];
                  while (mixin) {
                      clss.unshift(mixin);
                      mixin = mixin.superclass;
                  }
                  result = result.concat(clss);
              });
  
              result = uniq(result);
  
              result = result.filter(function(mixin){
                  var cls = ctor;
                  while (cls) {
                      if (mixin === cls) {
                          return false;
                      }
                      if (has(cls,"__mixins__")) {
                          var clsMixines = cls["__mixins__"];
                          for (var i=0; i<clsMixines.length;i++) {
                              if (clsMixines[i]===mixin) {
                                  return false;
                              }
                          }
                      }
                      cls = cls.superclass;
                  }
                  return true;
              });
  
              if (result.length>0) {
                  return result;
              } else {
                  return false;
              }
          }
  
          function mergeMixins(ctor,mixins) {
              var newCtor =ctor;
              for (var i=0;i<mixins.length;i++) {
                  var xtor = new Function();
                  xtor.prototype = Object.create(newCtor.prototype);
                  xtor.__proto__ = newCtor;
                  xtor.superclass = null;
                  mixin(xtor.prototype,mixins[i].prototype);
                  xtor.prototype.__mixin__ = mixins[i];
                  newCtor = xtor;
              }
  
              return newCtor;
          }
  
          return function createClass(props, parent, mixins,options) {
              if (isArray(parent)) {
                  options = mixins;
                  mixins = parent;
                  parent = null;
              }
              parent = parent || Object;
  
              if (isDefined(mixins) && !isArray(mixins)) {
                  options = mixins;
                  mixins = false;
              }
  
              var innerParent = parent;
  
              if (mixins) {
                  mixins = serialMixins(innerParent,mixins);
              }
  
              if (mixins) {
                  innerParent = mergeMixins(innerParent,mixins);
              }
  
  
              var _constructor = props.constructor;
              if (_constructor === Object) {
                  _constructor = function() {
                      if (this.init) {
                          return this.init.apply(this, arguments);
                      }
                  };
              };
  
              var klassName = props.klassName || "",
                  ctor = new Function(
                      "return function " + klassName + "() {" +
                      "var inst = this," +
                      " ctor = arguments.callee;" +
                      "if (!(inst instanceof ctor)) {" +
                      "inst = Object.create(ctor.prototype);" +
                      "}" +
                      "return ctor._constructor.apply(inst, arguments) || inst;" + 
                      "}"
                  )();
  
  
              ctor._constructor = _constructor;
              // Populate our constructed prototype object
              ctor.prototype = Object.create(innerParent.prototype);
  
              // Enforce the constructor to be what we expect
              ctor.prototype.constructor = ctor;
              ctor.superclass = parent;
  
              // And make this class extendable
              ctor.__proto__ = innerParent;
  
              if (mixins) {
                  ctor.__mixins__ = mixins;
              }
  
              if (!ctor.partial) {
                  ctor.partial = function(props, options) {
                      return extendClass(this, props, options);
                  };
              }
              if (!ctor.inherit) {
                  ctor.inherit = function(props, mixins,options) {
                      return createClass(props, this, mixins,options);
                  };
              }
  
              ctor.partial(props, options);
  
              return ctor;
          };
      }
  
      var createClass = f1();
  
      return createClass;
  });
  define('skylark-langx/ArrayStore',[
      "./klass"
  ],function(klass){
      var SimpleQueryEngine = function(query, options){
          // summary:
          //      Simple query engine that matches using filter functions, named filter
          //      functions or objects by name-value on a query object hash
          //
          // description:
          //      The SimpleQueryEngine provides a way of getting a QueryResults through
          //      the use of a simple object hash as a filter.  The hash will be used to
          //      match properties on data objects with the corresponding value given. In
          //      other words, only exact matches will be returned.
          //
          //      This function can be used as a template for more complex query engines;
          //      for example, an engine can be created that accepts an object hash that
          //      contains filtering functions, or a string that gets evaluated, etc.
          //
          //      When creating a new dojo.store, simply set the store's queryEngine
          //      field as a reference to this function.
          //
          // query: Object
          //      An object hash with fields that may match fields of items in the store.
          //      Values in the hash will be compared by normal == operator, but regular expressions
          //      or any object that provides a test() method are also supported and can be
          //      used to match strings by more complex expressions
          //      (and then the regex's or object's test() method will be used to match values).
          //
          // options: dojo/store/api/Store.QueryOptions?
          //      An object that contains optional information such as sort, start, and count.
          //
          // returns: Function
          //      A function that caches the passed query under the field "matches".  See any
          //      of the "query" methods on dojo.stores.
          //
          // example:
          //      Define a store with a reference to this engine, and set up a query method.
          //
          //  |   var myStore = function(options){
          //  |       //  ...more properties here
          //  |       this.queryEngine = SimpleQueryEngine;
          //  |       //  define our query method
          //  |       this.query = function(query, options){
          //  |           return QueryResults(this.queryEngine(query, options)(this.data));
          //  |       };
          //  |   };
  
          // create our matching query function
          switch(typeof query){
              default:
                  throw new Error("Can not query with a " + typeof query);
              case "object": case "undefined":
                  var queryObject = query;
                  query = function(object){
                      for(var key in queryObject){
                          var required = queryObject[key];
                          if(required && required.test){
                              // an object can provide a test method, which makes it work with regex
                              if(!required.test(object[key], object)){
                                  return false;
                              }
                          }else if(required != object[key]){
                              return false;
                          }
                      }
                      return true;
                  };
                  break;
              case "string":
                  // named query
                  if(!this[query]){
                      throw new Error("No filter function " + query + " was found in store");
                  }
                  query = this[query];
                  // fall through
              case "function":
                  // fall through
          }
          
          function filter(arr, callback, thisObject){
              // summary:
              //      Returns a new Array with those items from arr that match the
              //      condition implemented by callback.
              // arr: Array
              //      the array to iterate over.
              // callback: Function|String
              //      a function that is invoked with three arguments (item,
              //      index, array). The return of this function is expected to
              //      be a boolean which determines whether the passed-in item
              //      will be included in the returned array.
              // thisObject: Object?
              //      may be used to scope the call to callback
              // returns: Array
              // description:
              //      This function corresponds to the JavaScript 1.6 Array.filter() method, with one difference: when
              //      run over sparse arrays, this implementation passes the "holes" in the sparse array to
              //      the callback function with a value of undefined. JavaScript 1.6's filter skips the holes in the sparse array.
              //      For more details, see:
              //      https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/filter
              // example:
              //  | // returns [2, 3, 4]
              //  | array.filter([1, 2, 3, 4], function(item){ return item>1; });
  
              // TODO: do we need "Ctr" here like in map()?
              var i = 0, l = arr && arr.length || 0, out = [], value;
              if(l && typeof arr == "string") arr = arr.split("");
              if(typeof callback == "string") callback = cache[callback] || buildFn(callback);
              if(thisObject){
                  for(; i < l; ++i){
                      value = arr[i];
                      if(callback.call(thisObject, value, i, arr)){
                          out.push(value);
                      }
                  }
              }else{
                  for(; i < l; ++i){
                      value = arr[i];
                      if(callback(value, i, arr)){
                          out.push(value);
                      }
                  }
              }
              return out; // Array
          }
  
          function execute(array){
              // execute the whole query, first we filter
              var results = filter(array, query);
              // next we sort
              var sortSet = options && options.sort;
              if(sortSet){
                  results.sort(typeof sortSet == "function" ? sortSet : function(a, b){
                      for(var sort, i=0; sort = sortSet[i]; i++){
                          var aValue = a[sort.attribute];
                          var bValue = b[sort.attribute];
                          // valueOf enables proper comparison of dates
                          aValue = aValue != null ? aValue.valueOf() : aValue;
                          bValue = bValue != null ? bValue.valueOf() : bValue;
                          if (aValue != bValue){
                              // modified by lwf 2016/07/09
                              //return !!sort.descending == (aValue == null || aValue > bValue) ? -1 : 1;
                              return !!sort.descending == (aValue == null || aValue > bValue) ? -1 : 1;
                          }
                      }
                      return 0;
                  });
              }
              // now we paginate
              if(options && (options.start || options.count)){
                  var total = results.length;
                  results = results.slice(options.start || 0, (options.start || 0) + (options.count || Infinity));
                  results.total = total;
              }
              return results;
          }
          execute.matches = query;
          return execute;
      };
  
      var QueryResults = function(results){
          // summary:
          //      A function that wraps the results of a store query with additional
          //      methods.
          // description:
          //      QueryResults is a basic wrapper that allows for array-like iteration
          //      over any kind of returned data from a query.  While the simplest store
          //      will return a plain array of data, other stores may return deferreds or
          //      promises; this wrapper makes sure that *all* results can be treated
          //      the same.
          //
          //      Additional methods include `forEach`, `filter` and `map`.
          // results: Array|dojo/promise/Promise
          //      The result set as an array, or a promise for an array.
          // returns:
          //      An array-like object that can be used for iterating over.
          // example:
          //      Query a store and iterate over the results.
          //
          //  |   store.query({ prime: true }).forEach(function(item){
          //  |       //  do something
          //  |   });
  
          if(!results){
              return results;
          }
  
          var isPromise = !!results.then;
          // if it is a promise it may be frozen
          if(isPromise){
              results = Object.delegate(results);
          }
          function addIterativeMethod(method){
              // Always add the iterative methods so a QueryResults is
              // returned whether the environment is ES3 or ES5
              results[method] = function(){
                  var args = arguments;
                  var result = Deferred.when(results, function(results){
                      //Array.prototype.unshift.call(args, results);
                      return QueryResults(Array.prototype[method].apply(results, args));
                  });
                  // forEach should only return the result of when()
                  // when we're wrapping a promise
                  if(method !== "forEach" || isPromise){
                      return result;
                  }
              };
          }
  
          addIterativeMethod("forEach");
          addIterativeMethod("filter");
          addIterativeMethod("map");
          if(results.total == null){
              results.total = Deferred.when(results, function(results){
                  return results.length;
              });
          }
          return results; // Object
      };
  
      var ArrayStore = klass({
          "klassName": "ArrayStore",
  
          "queryEngine": SimpleQueryEngine,
          
          "idProperty": "id",
  
  
          get: function(id){
              // summary:
              //      Retrieves an object by its identity
              // id: Number
              //      The identity to use to lookup the object
              // returns: Object
              //      The object in the store that matches the given id.
              return this.data[this.index[id]];
          },
  
          getIdentity: function(object){
              return object[this.idProperty];
          },
  
          put: function(object, options){
              var data = this.data,
                  index = this.index,
                  idProperty = this.idProperty;
              var id = object[idProperty] = (options && "id" in options) ? options.id : idProperty in object ? object[idProperty] : Math.random();
              if(id in index){
                  // object exists
                  if(options && options.overwrite === false){
                      throw new Error("Object already exists");
                  }
                  // replace the entry in data
                  data[index[id]] = object;
              }else{
                  // add the new object
                  index[id] = data.push(object) - 1;
              }
              return id;
          },
  
          add: function(object, options){
              (options = options || {}).overwrite = false;
              // call put with overwrite being false
              return this.put(object, options);
          },
  
          remove: function(id){
              // summary:
              //      Deletes an object by its identity
              // id: Number
              //      The identity to use to delete the object
              // returns: Boolean
              //      Returns true if an object was removed, falsy (undefined) if no object matched the id
              var index = this.index;
              var data = this.data;
              if(id in index){
                  data.splice(index[id], 1);
                  // now we have to reindex
                  this.setData(data);
                  return true;
              }
          },
          query: function(query, options){
              // summary:
              //      Queries the store for objects.
              // query: Object
              //      The query to use for retrieving objects from the store.
              // options: dojo/store/api/Store.QueryOptions?
              //      The optional arguments to apply to the resultset.
              // returns: dojo/store/api/Store.QueryResults
              //      The results of the query, extended with iterative methods.
              //
              // example:
              //      Given the following store:
              //
              //  |   var store = new Memory({
              //  |       data: [
              //  |           {id: 1, name: "one", prime: false },
              //  |           {id: 2, name: "two", even: true, prime: true},
              //  |           {id: 3, name: "three", prime: true},
              //  |           {id: 4, name: "four", even: true, prime: false},
              //  |           {id: 5, name: "five", prime: true}
              //  |       ]
              //  |   });
              //
              //  ...find all items where "prime" is true:
              //
              //  |   var results = store.query({ prime: true });
              //
              //  ...or find all items where "even" is true:
              //
              //  |   var results = store.query({ even: true });
              return QueryResults(this.queryEngine(query, options)(this.data));
          },
  
          setData: function(data){
              // summary:
              //      Sets the given data as the source for this store, and indexes it
              // data: Object[]
              //      An array of objects to use as the source of data.
              if(data.items){
                  // just for convenience with the data format IFRS expects
                  this.idProperty = data.identifier || this.idProperty;
                  data = this.data = data.items;
              }else{
                  this.data = data;
              }
              this.index = {};
              for(var i = 0, l = data.length; i < l; i++){
                  this.index[data[i][this.idProperty]] = i;
              }
          },
  
          init: function(options) {
              for(var i in options){
                  this[i] = options[i];
              }
              this.setData(this.data || []);
          }
  
      });
  
  	return ArrayStore;
  });
  define('skylark-langx/aspect',[
  ],function(){
  
    var undefined, nextId = 0;
      function advise(dispatcher, type, advice, receiveArguments){
          var previous = dispatcher[type];
          var around = type == "around";
          var signal;
          if(around){
              var advised = advice(function(){
                  return previous.advice(this, arguments);
              });
              signal = {
                  remove: function(){
                      if(advised){
                          advised = dispatcher = advice = null;
                      }
                  },
                  advice: function(target, args){
                      return advised ?
                          advised.apply(target, args) :  // called the advised function
                          previous.advice(target, args); // cancelled, skip to next one
                  }
              };
          }else{
              // create the remove handler
              signal = {
                  remove: function(){
                      if(signal.advice){
                          var previous = signal.previous;
                          var next = signal.next;
                          if(!next && !previous){
                              delete dispatcher[type];
                          }else{
                              if(previous){
                                  previous.next = next;
                              }else{
                                  dispatcher[type] = next;
                              }
                              if(next){
                                  next.previous = previous;
                              }
                          }
  
                          // remove the advice to signal that this signal has been removed
                          dispatcher = advice = signal.advice = null;
                      }
                  },
                  id: nextId++,
                  advice: advice,
                  receiveArguments: receiveArguments
              };
          }
          if(previous && !around){
              if(type == "after"){
                  // add the listener to the end of the list
                  // note that we had to change this loop a little bit to workaround a bizarre IE10 JIT bug
                  while(previous.next && (previous = previous.next)){}
                  previous.next = signal;
                  signal.previous = previous;
              }else if(type == "before"){
                  // add to beginning
                  dispatcher[type] = signal;
                  signal.next = previous;
                  previous.previous = signal;
              }
          }else{
              // around or first one just replaces
              dispatcher[type] = signal;
          }
          return signal;
      }
      function aspect(type){
          return function(target, methodName, advice, receiveArguments){
              var existing = target[methodName], dispatcher;
              if(!existing || existing.target != target){
                  // no dispatcher in place
                  target[methodName] = dispatcher = function(){
                      var executionId = nextId;
                      // before advice
                      var args = arguments;
                      var before = dispatcher.before;
                      while(before){
                          args = before.advice.apply(this, args) || args;
                          before = before.next;
                      }
                      // around advice
                      if(dispatcher.around){
                          var results = dispatcher.around.advice(this, args);
                      }
                      // after advice
                      var after = dispatcher.after;
                      while(after && after.id < executionId){
                          if(after.receiveArguments){
                              var newResults = after.advice.apply(this, args);
                              // change the return value only if a new value was returned
                              results = newResults === undefined ? results : newResults;
                          }else{
                              results = after.advice.call(this, results, args);
                          }
                          after = after.next;
                      }
                      return results;
                  };
                  if(existing){
                      dispatcher.around = {advice: function(target, args){
                          return existing.apply(target, args);
                      }};
                  }
                  dispatcher.target = target;
              }
              var results = advise((dispatcher || existing), type, advice, receiveArguments);
              advice = null;
              return results;
          };
      }
  
      return {
          after: aspect("after"),
   
          around: aspect("around"),
          
          before: aspect("before")
      };
  });
  define('skylark-langx/funcs',[
      "./objects",
  	"./types"
  ],function(objects,types){
  	var mixin = objects.mixin,
          isFunction = types.isFunction,
          isString = types.isString;
  
      function defer(fn) {
          if (requestAnimationFrame) {
              requestAnimationFrame(fn);
          } else {
              setTimeoutout(fn);
          }
          return this;
      }
  
      function noop() {
      }
  
      function proxy(fn, context) {
          var args = (2 in arguments) && slice.call(arguments, 2)
          if (isFunction(fn)) {
              var proxyFn = function() {
                  return fn.apply(context, args ? args.concat(slice.call(arguments)) : arguments);
              }
              return proxyFn;
          } else if (isString(context)) {
              if (args) {
                  args.unshift(fn[context], fn)
                  return proxy.apply(null, args)
              } else {
                  return proxy(fn[context], fn);
              }
          } else {
              throw new TypeError("expected function");
          }
      }
  
      function debounce(fn, wait) {
          var timeout;
          return function () {
              var context = this, args = arguments;
              var later = function () {
                  timeout = null;
                  fn.apply(context, args);
              };
              if (timeout) clearTimeout(timeout);
              timeout = setTimeout(later, wait);
          };
      }
     
      var delegate = (function() {
          // boodman/crockford delegation w/ cornford optimization
          function TMP() {}
          return function(obj, props) {
              TMP.prototype = obj;
              var tmp = new TMP();
              TMP.prototype = null;
              if (props) {
                  mixin(tmp, props);
              }
              return tmp; // Object
          };
      })();
  
  
      return {
          debounce: debounce,
  
          delegate: delegate,
  
          defer: defer,
  
          noop : noop,
  
          proxy: proxy,
  
          returnTrue: function() {
              return true;
          },
  
          returnFalse: function() {
              return false;
          }
      };
  });
  define('skylark-langx/Deferred',[
      "./arrays",
  	"./funcs",
      "./objects"
  ],function(arrays,funcs,objects){
      "use strict";
      
      var  PGLISTENERS = Symbol ? Symbol() : '__pglisteners';
  
      var slice = Array.prototype.slice,
          proxy = funcs.proxy,
          makeArray = arrays.makeArray,
          result = objects.result,
          mixin = objects.mixin;
  
      mixin(Promise.prototype,{
          always: function(handler) {
              //this.done(handler);
              //this.fail(handler);
              this.then(handler,handler);
              return this;
          },
          done : function(handler) {
              this.then(handler);
              return this;
          },
          fail : function(handler) { 
              //return mixin(Promise.prototype.catch.call(this,handler),added);
              //return this.then(null,handler);
              this.catch(handler);
              return this;
          }
      });
  
  
      var Deferred = function() {
          var self = this,
              p = this.promise = new Promise(function(resolve, reject) {
                  self._resolve = resolve;
                  self._reject = reject;
              });
  
          wrapPromise(p,self);
  
          this[PGLISTENERS] = [];
  
          //this.resolve = Deferred.prototype.resolve.bind(this);
          //this.reject = Deferred.prototype.reject.bind(this);
          //this.progress = Deferred.prototype.progress.bind(this);
  
      };
  
      function wrapPromise(p,d) {
          var   added = {
                  state : function() {
                      if (d.isResolved()) {
                          return 'resolved';
                      }
                      if (d.isRejected()) {
                          return 'rejected';
                      }
                      return 'pending';
                  },
                  then : function(onResolved,onRejected,onProgress) {
                      if (onProgress) {
                          this.progress(onProgress);
                      }
                      return mixin(Promise.prototype.then.call(this,
                              onResolved && function(args) {
                                  if (args && args.__ctx__ !== undefined) {
                                      return onResolved.apply(args.__ctx__,args);
                                  } else {
                                      return onResolved(args);
                                  }
                              },
                              onRejected && function(args){
                                  if (args && args.__ctx__ !== undefined) {
                                      return onRejected.apply(args.__ctx__,args);
                                  } else {
                                      return onRejected(args);
                                  }
                              }),added);
                  },
                  progress : function(handler) {
                      d[PGLISTENERS].push(handler);
                      return this;
                  }
  
              };
  
          added.pipe = added.then;
          return mixin(p,added);
  
      }
  
      Deferred.prototype.resolve = function(value) {
          var args = slice.call(arguments);
          return this.resolveWith(null,args);
      };
  
      Deferred.prototype.resolveWith = function(context,args) {
          args = args ? makeArray(args) : []; 
          args.__ctx__ = context;
          this._resolve(args);
          this._resolved = true;
          return this;
      };
  
      Deferred.prototype.progress = function(value) {
          try {
            return this[PGLISTENERS].forEach(function (listener) {
              return listener(value);
            });
          } catch (error) {
            this.reject(error);
          }
          return this;
      };
  
      Deferred.prototype.reject = function(reason) {
          var args = slice.call(arguments);
          return this.rejectWith(null,args);
      };
  
      Deferred.prototype.rejectWith = function(context,args) {
          args = args ? makeArray(args) : []; 
          args.__ctx__ = context;
          this._reject(args);
          this._rejected = true;
          return this;
      };
  
      Deferred.prototype.isResolved = function() {
          return !!this._resolved;
      };
  
      Deferred.prototype.isRejected = function() {
          return !!this._rejected;
      };
  
      Deferred.prototype.then = function(callback, errback, progback) {
          var p = result(this,"promise");
          return p.then(callback, errback, progback);
      };
  
      Deferred.prototype.done  = Deferred.prototype.then;
  
      Deferred.all = function(array) {
          return wrapPromise(Promise.all(array));
      };
  
      Deferred.first = function(array) {
          return wrapPromise(Promise.race(array));
      };
  
  
      Deferred.when = function(valueOrPromise, callback, errback, progback) {
          var receivedPromise = valueOrPromise && typeof valueOrPromise.then === "function";
          var nativePromise = receivedPromise && valueOrPromise instanceof Promise;
  
          if (!receivedPromise) {
              if (arguments.length > 1) {
                  return callback ? callback(valueOrPromise) : valueOrPromise;
              } else {
                  return new Deferred().resolve(valueOrPromise);
              }
          } else if (!nativePromise) {
              var deferred = new Deferred(valueOrPromise.cancel);
              valueOrPromise.then(proxy(deferred.resolve,deferred), proxy(deferred.reject,deferred), deferred.progress);
              valueOrPromise = deferred.promise;
          }
  
          if (callback || errback || progback) {
              return valueOrPromise.then(callback, errback, progback);
          }
          return valueOrPromise;
      };
  
      Deferred.reject = function(err) {
          var d = new Deferred();
          d.reject(err);
          return d.promise;
      };
  
      Deferred.resolve = function(data) {
          var d = new Deferred();
          d.resolve.apply(d,arguments);
          return d.promise;
      };
  
      Deferred.immediate = Deferred.resolve;
  
      return Deferred;
  });
  define('skylark-langx/async',[
      "./Deferred",
      "./arrays"
  ],function(Deferred,arrays){
      var each = arrays.each;
      
      var async = {
          parallel : function(arr,args,ctx) {
              var rets = [];
              ctx = ctx || null;
              args = args || [];
  
              each(arr,function(i,func){
                  rets.push(func.apply(ctx,args));
              });
  
              return Deferred.all(rets);
          },
  
          series : function(arr,args,ctx) {
              var rets = [],
                  d = new Deferred(),
                  p = d.promise;
  
              ctx = ctx || null;
              args = args || [];
  
              d.resolve();
              each(arr,function(i,func){
                  p = p.then(function(){
                      return func.apply(ctx,args);
                  });
                  rets.push(p);
              });
  
              return Deferred.all(rets);
          },
  
          waterful : function(arr,args,ctx) {
              var d = new Deferred(),
                  p = d.promise;
  
              ctx = ctx || null;
              args = args || [];
  
              d.resolveWith(ctx,args);
  
              each(arr,function(i,func){
                  p = p.then(func);
              });
              return p;
          }
      };
  
  	return async;	
  });
  define('skylark-langx/Evented',[
      "./klass",
      "./objects",
  	"./types"
  ],function(klass,objects,types){
  	var slice = Array.prototype.slice,
          isDefined = types.isDefined,
          isPlainObject = types.isPlainObject,
  		isFunction = types.isFunction,
  		isString = types.isString,
  		isEmptyObject = types.isEmptyObject,
  		mixin = objects.mixin;
  
      var Evented = klass({
          on: function(events, selector, data, callback, ctx, /*used internally*/ one) {
              var self = this,
                  _hub = this._hub || (this._hub = {});
  
              if (isPlainObject(events)) {
                  ctx = callback;
                  each(events, function(type, fn) {
                      self.on(type, selector, data, fn, ctx, one);
                  });
                  return this;
              }
  
              if (!isString(selector) && !isFunction(callback)) {
                  ctx = callback;
                  callback = data;
                  data = selector;
                  selector = undefined;
              }
  
              if (isFunction(data)) {
                  ctx = callback;
                  callback = data;
                  data = null;
              }
  
              if (isString(events)) {
                  events = events.split(/\s/)
              }
  
              events.forEach(function(name) {
                  (_hub[name] || (_hub[name] = [])).push({
                      fn: callback,
                      selector: selector,
                      data: data,
                      ctx: ctx,
                      one: one
                  });
              });
  
              return this;
          },
  
          one: function(events, selector, data, callback, ctx) {
              return this.on(events, selector, data, callback, ctx, 1);
          },
  
          trigger: function(e /*,argument list*/ ) {
              if (!this._hub) {
                  return this;
              }
  
              var self = this;
  
              if (isString(e)) {
                  e = new CustomEvent(e);
              }
  
              Object.defineProperty(e,"target",{
                  value : this
              });
  
              var args = slice.call(arguments, 1);
              if (isDefined(args)) {
                  args = [e].concat(args);
              } else {
                  args = [e];
              }
              [e.type || e.name, "all"].forEach(function(eventName) {
                  var listeners = self._hub[eventName];
                  if (!listeners) {
                      return;
                  }
  
                  var len = listeners.length,
                      reCompact = false;
  
                  for (var i = 0; i < len; i++) {
                      var listener = listeners[i];
                      if (e.data) {
                          if (listener.data) {
                              e.data = mixin({}, listener.data, e.data);
                          }
                      } else {
                          e.data = listener.data || null;
                      }
                      listener.fn.apply(listener.ctx, args);
                      if (listener.one) {
                          listeners[i] = null;
                          reCompact = true;
                      }
                  }
  
                  if (reCompact) {
                      self._hub[eventName] = compact(listeners);
                  }
  
              });
              return this;
          },
  
          listened: function(event) {
              var evtArr = ((this._hub || (this._events = {}))[event] || []);
              return evtArr.length > 0;
          },
  
          listenTo: function(obj, event, callback, /*used internally*/ one) {
              if (!obj) {
                  return this;
              }
  
              // Bind callbacks on obj,
              if (isString(callback)) {
                  callback = this[callback];
              }
  
              if (one) {
                  obj.one(event, callback, this);
              } else {
                  obj.on(event, callback, this);
              }
  
              //keep track of them on listening.
              var listeningTo = this._listeningTo || (this._listeningTo = []),
                  listening;
  
              for (var i = 0; i < listeningTo.length; i++) {
                  if (listeningTo[i].obj == obj) {
                      listening = listeningTo[i];
                      break;
                  }
              }
              if (!listening) {
                  listeningTo.push(
                      listening = {
                          obj: obj,
                          events: {}
                      }
                  );
              }
              var listeningEvents = listening.events,
                  listeningEvent = listeningEvents[event] = listeningEvents[event] || [];
              if (listeningEvent.indexOf(callback) == -1) {
                  listeningEvent.push(callback);
              }
  
              return this;
          },
  
          listenToOnce: function(obj, event, callback) {
              return this.listenTo(obj, event, callback, 1);
          },
  
          off: function(events, callback) {
              var _hub = this._hub || (this._hub = {});
              if (isString(events)) {
                  events = events.split(/\s/)
              }
  
              events.forEach(function(name) {
                  var evts = _hub[name];
                  var liveEvents = [];
  
                  if (evts && callback) {
                      for (var i = 0, len = evts.length; i < len; i++) {
                          if (evts[i].fn !== callback && evts[i].fn._ !== callback)
                              liveEvents.push(evts[i]);
                      }
                  }
  
                  if (liveEvents.length) {
                      _hub[name] = liveEvents;
                  } else {
                      delete _hub[name];
                  }
              });
  
              return this;
          },
          unlistenTo: function(obj, event, callback) {
              var listeningTo = this._listeningTo;
              if (!listeningTo) {
                  return this;
              }
              for (var i = 0; i < listeningTo.length; i++) {
                  var listening = listeningTo[i];
  
                  if (obj && obj != listening.obj) {
                      continue;
                  }
  
                  var listeningEvents = listening.events;
                  for (var eventName in listeningEvents) {
                      if (event && event != eventName) {
                          continue;
                      }
  
                      var listeningEvent = listeningEvents[eventName];
  
                      for (var j = 0; j < listeningEvent.length; j++) {
                          if (!callback || callback == listeningEvent[i]) {
                              listening.obj.off(eventName, listeningEvent[i], this);
                              listeningEvent[i] = null;
                          }
                      }
  
                      listeningEvent = listeningEvents[eventName] = compact(listeningEvent);
  
                      if (isEmptyObject(listeningEvent)) {
                          listeningEvents[eventName] = null;
                      }
  
                  }
  
                  if (isEmptyObject(listeningEvents)) {
                      listeningTo[i] = null;
                  }
              }
  
              listeningTo = this._listeningTo = compact(listeningTo);
              if (isEmptyObject(listeningTo)) {
                  this._listeningTo = null;
              }
  
              return this;
          }
      });
  
  	return Evented;
  
  });
  define('skylark-langx/strings',[
  ],function(){
  
       /*
       * Converts camel case into dashes.
       * @param {String} str
       * @return {String}
       * @exapmle marginTop -> margin-top
       */
      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();
      }
  
      function deserializeValue(value) {
          try {
              return value ?
                  value == "true" ||
                  (value == "false" ? false :
                      value == "null" ? null :
                      +value + "" == value ? +value :
                      /^[\[\{]/.test(value) ? JSON.parse(value) :
                      value) : value;
          } catch (e) {
              return value;
          }
      }
  
      function trim(str) {
          return str == null ? "" : String.prototype.trim.call(str);
      }
      function substitute( /*String*/ template,
          /*Object|Array*/
          map,
          /*Function?*/
          transform,
          /*Object?*/
          thisObject) {
          // summary:
          //    Performs parameterized substitutions on a string. Throws an
          //    exception if any parameter is unmatched.
          // template:
          //    a string with expressions in the form `${key}` to be replaced or
          //    `${key:format}` which specifies a format function. keys are case-sensitive.
          // map:
          //    hash to search for substitutions
          // transform:
          //    a function to process all parameters before substitution takes
  
  
          thisObject = thisObject || window;
          transform = transform ?
              proxy(thisObject, transform) : function(v) {
                  return v;
              };
  
          function getObject(key, map) {
              if (key.match(/\./)) {
                  var retVal,
                      getValue = function(keys, obj) {
                          var _k = keys.pop();
                          if (_k) {
                              if (!obj[_k]) return null;
                              return getValue(keys, retVal = obj[_k]);
                          } else {
                              return retVal;
                          }
                      };
                  return getValue(key.split(".").reverse(), map);
              } else {
                  return map[key];
              }
          }
  
          return template.replace(/\$\{([^\s\:\}]+)(?:\:([^\s\:\}]+))?\}/g,
              function(match, key, format) {
                  var value = getObject(key, map);
                  if (format) {
                      value = getObject(format, thisObject).call(thisObject, value, key);
                  }
                  return transform(value, key).toString();
              }); // String
      }
  
  	return {
          camelCase: function(str) {
              return str.replace(/-([\da-z])/g, function(a) {
                  return a.toUpperCase().replace('-', '');
              });
          },
  
  
          dasherize: dasherize,
  
          deserializeValue: deserializeValue,
  
          lowerFirst: function(str) {
              return str.charAt(0).toLowerCase() + str.slice(1);
          },
  
          serializeValue: function(value) {
              return JSON.stringify(value)
          },
  
  
          substitute: substitute,
  
          trim: trim,
  
          upperFirst: function(str) {
              return str.charAt(0).toUpperCase() + str.slice(1);
          }
  	} ; 
  
  });
  define('skylark-langx/Xhr',[
      "./arrays",
      "./Deferred",
      "./Evented",
      "./objects",
      "./funcs",
      "./types"
  ],function(arrays,Deferred,Evented,objects,funcs,types){
      var each = arrays.each,
          mixin = objects.mixin,
          noop = funcs.noop,
          isArray = types.isArray,
          isFunction = types.isFunction,
          isPlainObject = types.isPlainObject,
          type = types.type;
   
       var getAbsoluteUrl = (function() {
          var a;
  
          return function(url) {
              if (!a) a = document.createElement('a');
              a.href = url;
  
              return a.href;
          };
      })();
     
      var Xhr = (function(){
          var jsonpID = 0,
              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*$/;
  
          var XhrDefaultOptions = {
              async: true,
  
              // Default type of request
              type: 'GET',
              // Callback that is executed before request
              beforeSend: noop,
              // Callback that is executed if the request succeeds
              success: noop,
              // Callback that is executed the the server drops error
              error: noop,
              // Callback that is executed on request complete (both: error and success)
              complete: noop,
              // The context for the callbacks
              context: null,
              // Whether to trigger "global" Ajax events
              global: true,
  
              // MIME types mapping
              // IIS returns Javascript as "application/x-javascript"
              accepts: {
                  script: 'text/javascript, application/javascript, application/x-javascript',
                  json: 'application/json',
                  xml: 'application/xml, text/xml',
                  html: 'text/html',
                  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,
  
              xhrFields : {
                  withCredentials : true
              }
          };
  
          function mimeToDataType(mime) {
              if (mime) {
                  mime = mime.split(';', 2)[0];
              }
              if (mime) {
                  if (mime == htmlType) {
                      return "html";
                  } else if (mime == jsonType) {
                      return "json";
                  } else if (scriptTypeRE.test(mime)) {
                      return "script";
                  } else if (xmlTypeRE.test(mime)) {
                      return "xml";
                  }
              }
              return "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) {
              options.data = options.data || options.query;
              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;
              }
          }
  
          function serialize(params, obj, traditional, scope) {
              var t, array = isArray(obj),
                  hash = isPlainObject(obj)
              each(obj, function(key, value) {
                  t =type(value);
                  if (scope) key = traditional ? scope :
                      scope + '[' + (hash || t == 'object' || t == 'array' ? key : '') + ']'
                  // handle data in serializeArray() format
                  if (!scope && array) params.add(value.name, value.value)
                  // recurse into nested objects
                  else if (t == "array" || (!traditional && t == "object"))
                      serialize(params, value, traditional, key)
                  else params.add(key, value)
              })
          }
  
          var param = function(obj, traditional) {
              var params = []
              params.add = function(key, value) {
                  if (isFunction(value)) value = value()
                  if (value == null) value = ""
                  this.push(escape(key) + '=' + escape(value))
              }
              serialize(params, obj, traditional)
              return params.join('&').replace(/%20/g, '+')
          };
  
          var Xhr = Evented.inherit({
              klassName : "Xhr",
  
              _request  : function(args) {
                  var _ = this._,
                      self = this,
                      options = mixin({},XhrDefaultOptions,_.options,args),
                      xhr = _.xhr = new XMLHttpRequest();
  
                  serializeData(options)
  
                  var dataType = options.dataType || options.handleAs,
                      mime = options.mimeType || options.accepts[dataType],
                      headers = options.headers,
                      xhrFields = options.xhrFields,
                      isFormData = options.data && options.data instanceof FormData,
                      basicAuthorizationToken = options.basicAuthorizationToken,
                      type = options.type,
                      url = options.url,
                      async = options.async,
                      user = options.user , 
                      password = options.password,
                      deferred = new Deferred(),
                      contentType = isFormData ? false : 'application/x-www-form-urlencoded';
  
                  if (xhrFields) {
                      for (name in xhrFields) {
                          xhr[name] = xhrFields[name];
                      }
                  }
  
                  if (mime && mime.indexOf(',') > -1) {
                      mime = mime.split(',', 2)[0];
                  }
                  if (mime && xhr.overrideMimeType) {
                      xhr.overrideMimeType(mime);
                  }
  
                  //if (dataType) {
                  //    xhr.responseType = dataType;
                  //}
  
                  var finish = function() {
                      xhr.onloadend = noop;
                      xhr.onabort = noop;
                      xhr.onprogress = noop;
                      xhr.ontimeout = noop;
                      xhr = null;
                  }
                  var onloadend = function() {
                      var result, error = false
                      if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304 || (xhr.status == 0 && getAbsoluteUrl(url).startsWith('file:'))) {
                          dataType = dataType || mimeToDataType(options.mimeType || xhr.getResponseHeader('content-type'));
  
                          result = xhr.responseText;
                          try {
                              if (dataType == 'script') {
                                  eval(result);
                              } else if (dataType == 'xml') {
                                  result = xhr.responseXML;
                              } else if (dataType == 'json') {
                                  result = blankRE.test(result) ? null : JSON.parse(result);
                              } else if (dataType == "blob") {
                                  result = Blob([xhrObj.response]);
                              } else if (dataType == "arraybuffer") {
                                  result = xhr.reponse;
                              }
                          } catch (e) { 
                              error = e;
                          }
  
                          if (error) {
                              deferred.reject(error,xhr.status,xhr);
                          } else {
                              deferred.resolve(result,xhr.status,xhr);
                          }
                      } else {
                          deferred.reject(new Error(xhr.statusText),xhr.status,xhr);
                      }
                      finish();
                  };
  
                  var onabort = function() {
                      if (deferred) {
                          deferred.reject(new Error("abort"),xhr.status,xhr);
                      }
                      finish();                 
                  }
   
                  var ontimeout = function() {
                      if (deferred) {
                          deferred.reject(new Error("timeout"),xhr.status,xhr);
                      }
                      finish();                 
                  }
  
                  var onprogress = function(evt) {
                      if (deferred) {
                          deferred.progress(evt,xhr.status,xhr);
                      }
                  }
  
                  xhr.onloadend = onloadend;
                  xhr.onabort = onabort;
                  xhr.ontimeout = ontimeout;
                  xhr.onprogress = onprogress;
  
                  xhr.open(type, url, async, user, password);
                 
                  if (headers) {
                      for ( var key in headers) {
                          var value = headers[key];
   
                          if(key.toLowerCase() === 'content-type'){
                              contentType = headers[hdr];
                          } else {
                             xhr.setRequestHeader(key, value);
                          }
                      }
                  }   
  
                  if  (contentType && contentType !== false){
                      xhr.setRequestHeader('Content-Type', contentType);
                  }
  
                  if(!headers || !('X-Requested-With' in headers)){
                      xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
                  }
  
  
                  //If basicAuthorizationToken is defined set its value into "Authorization" header
                  if (basicAuthorizationToken) {
                      xhr.setRequestHeader("Authorization", basicAuthorizationToken);
                  }
  
                  xhr.send(options.data ? options.data : null);
  
                  return deferred.promise;
  
              },
  
              "abort": function() {
                  var _ = this._,
                      xhr = _.xhr;
  
                  if (xhr) {
                      xhr.abort();
                  }    
              },
  
  
              "request": function(args) {
                  return this._request(args);
              },
  
              get : function(args) {
                  args = args || {};
                  args.type = "GET";
                  return this._request(args);
              },
  
              post : function(args) {
                  args = args || {};
                  args.type = "POST";
                  return this._request(args);
              },
  
              patch : function(args) {
                  args = args || {};
                  args.type = "PATCH";
                  return this._request(args);
              },
  
              put : function(args) {
                  args = args || {};
                  args.type = "PUT";
                  return this._request(args);
              },
  
              del : function(args) {
                  args = args || {};
                  args.type = "DELETE";
                  return this._request(args);
              },
  
              "init": function(options) {
                  this._ = {
                      options : options || {}
                  };
              }
          });
  
          ["request","get","post","put","del","patch"].forEach(function(name){
              Xhr[name] = function(url,args) {
                  var xhr = new Xhr({"url" : url});
                  return xhr[name](args);
              };
          });
  
          Xhr.defaultOptions = XhrDefaultOptions;
          Xhr.param = param;
  
          return Xhr;
      })();
  
  	return Xhr;	
  });
  define('skylark-langx/Restful',[
      "./Evented",
      "./objects",
      "./strings",
      "./Xhr"
  ],function(Evented,objects,strings,Xhr){
      var mixin = objects.mixin,
          substitute = strings.substitute;
  
      var Restful = Evented.inherit({
          "klassName" : "Restful",
  
          "idAttribute": "id",
          
          getBaseUrl : function(args) {
              //$$baseEndpoint : "/files/${fileId}/comments",
              var baseEndpoint = substitute(this.baseEndpoint,args),
                  baseUrl = this.server + this.basePath + baseEndpoint;
              if (args[this.idAttribute]!==undefined) {
                  baseUrl = baseUrl + "/" + args[this.idAttribute]; 
              }
              return baseUrl;
          },
          _head : function(args) {
              //get resource metadata .
              //args : id and other info for the resource ,ex
              //{
              //  "id" : 234,  // the own id, required
              //  "fileId"   : 2 // the parent resource id, option by resource
              //}
          },
          _get : function(args) {
              //get resource ,one or list .
              //args : id and other info for the resource ,ex
              //{
              //  "id" : 234,  // the own id, null if list
              //  "fileId"   : 2 // the parent resource id, option by resource
              //}
              return Xhr.get(this.getBaseUrl(args),args);
          },
          _post  : function(args,verb) {
              //create or move resource .
              //args : id and other info for the resource ,ex
              //{
              //  "id" : 234,  // the own id, required
              //  "data" : body // the own data,required
              //  "fileId"   : 2 // the parent resource id, option by resource
              //}
              //verb : the verb ,ex: copy,touch,trash,untrash,watch
              var url = this.getBaseUrl(args);
              if (verb) {
                  url = url + "/" + verb;
              }
              return Xhr.post(url, args);
          },
  
          _put  : function(args,verb) {
              //update resource .
              //args : id and other info for the resource ,ex
              //{
              //  "id" : 234,  // the own id, required
              //  "data" : body // the own data,required
              //  "fileId"   : 2 // the parent resource id, option by resource
              //}
              //verb : the verb ,ex: copy,touch,trash,untrash,watch
              var url = this.getBaseUrl(args);
              if (verb) {
                  url = url + "/" + verb;
              }
              return Xhr.put(url, args);
          },
  
          _delete : function(args) {
              //delete resource . 
              //args : id and other info for the resource ,ex
              //{
              //  "id" : 234,  // the own id, required
              //  "fileId"   : 2 // the parent resource id, option by resource
              //}         
  
              // HTTP request : DELETE http://center.utilhub.com/registry/v1/apps/{appid}
              var url = this.getBaseUrl(args);
              return Xhr.del(url);
          },
  
          _patch : function(args){
              //update resource metadata. 
              //args : id and other info for the resource ,ex
              //{
              //  "id" : 234,  // the own id, required
              //  "data" : body // the own data,required
              //  "fileId"   : 2 // the parent resource id, option by resource
              //}
              var url = this.getBaseUrl(args);
              return Xhr.patch(url, args);
          },
          query: function(params) {
              
              return this._post(params);
          },
  
          retrieve: function(params) {
              return this._get(params);
          },
  
          create: function(params) {
              return this._post(params);
          },
  
          update: function(params) {
              return this._put(params);
          },
  
          delete: function(params) {
              // HTTP request : DELETE http://center.utilhub.com/registry/v1/apps/{appid}
              return this._delete(params);
          },
  
          patch: function(params) {
             // HTTP request : PATCH http://center.utilhub.com/registry/v1/apps/{appid}
              return this._patch(params);
          },
          init: function(params) {
              mixin(this,params);
   //           this._xhr = XHRx();
         }
      });
  
      return Restful;
  });
  define('skylark-langx/Stateful',[
  	"./Evented"
  ],function(Evented){
      var Stateful = Evented.inherit({
          init : function(attributes, options) {
              var attrs = attributes || {};
              options || (options = {});
              this.cid = uniqueId(this.cidPrefix);
              this.attributes = {};
              if (options.collection) this.collection = options.collection;
              if (options.parse) attrs = this.parse(attrs, options) || {};
              var defaults = result(this, 'defaults');
              attrs = mixin({}, defaults, attrs);
              this.set(attrs, options);
              this.changed = {};
          },
  
          // A hash of attributes whose current and previous value differ.
          changed: null,
  
          // The value returned during the last failed validation.
          validationError: null,
  
          // The default name for the JSON `id` attribute is `"id"`. MongoDB and
          // CouchDB users may want to set this to `"_id"`.
          idAttribute: 'id',
  
          // The prefix is used to create the client id which is used to identify models locally.
          // You may want to override this if you're experiencing name clashes with model ids.
          cidPrefix: 'c',
  
  
          // Return a copy of the model's `attributes` object.
          toJSON: function(options) {
            return clone(this.attributes);
          },
  
  
          // Get the value of an attribute.
          get: function(attr) {
            return this.attributes[attr];
          },
  
          // Returns `true` if the attribute contains a value that is not null
          // or undefined.
          has: function(attr) {
            return this.get(attr) != null;
          },
  
          // Set a hash of model attributes on the object, firing `"change"`. This is
          // the core primitive operation of a model, updating the data and notifying
          // anyone who needs to know about the change in state. The heart of the beast.
          set: function(key, val, options) {
            if (key == null) return this;
  
            // Handle both `"key", value` and `{key: value}` -style arguments.
            var attrs;
            if (typeof key === 'object') {
              attrs = key;
              options = val;
            } else {
              (attrs = {})[key] = val;
            }
  
            options || (options = {});
  
            // Run validation.
            if (!this._validate(attrs, options)) return false;
  
            // Extract attributes and options.
            var unset      = options.unset;
            var silent     = options.silent;
            var changes    = [];
            var changing   = this._changing;
            this._changing = true;
  
            if (!changing) {
              this._previousAttributes = clone(this.attributes);
              this.changed = {};
            }
  
            var current = this.attributes;
            var changed = this.changed;
            var prev    = this._previousAttributes;
  
            // For each `set` attribute, update or delete the current value.
            for (var attr in attrs) {
              val = attrs[attr];
              if (!isEqual(current[attr], val)) changes.push(attr);
              if (!isEqual(prev[attr], val)) {
                changed[attr] = val;
              } else {
                delete changed[attr];
              }
              unset ? delete current[attr] : current[attr] = val;
            }
  
            // Update the `id`.
            if (this.idAttribute in attrs) this.id = this.get(this.idAttribute);
  
            // Trigger all relevant attribute changes.
            if (!silent) {
              if (changes.length) this._pending = options;
              for (var i = 0; i < changes.length; i++) {
                this.trigger('change:' + changes[i], this, current[changes[i]], options);
              }
            }
  
            // You might be wondering why there's a `while` loop here. Changes can
            // be recursively nested within `"change"` events.
            if (changing) return this;
            if (!silent) {
              while (this._pending) {
                options = this._pending;
                this._pending = false;
                this.trigger('change', this, options);
              }
            }
            this._pending = false;
            this._changing = false;
            return this;
          },
  
          // Remove an attribute from the model, firing `"change"`. `unset` is a noop
          // if the attribute doesn't exist.
          unset: function(attr, options) {
            return this.set(attr, void 0, mixin({}, options, {unset: true}));
          },
  
          // Clear all attributes on the model, firing `"change"`.
          clear: function(options) {
            var attrs = {};
            for (var key in this.attributes) attrs[key] = void 0;
            return this.set(attrs, mixin({}, options, {unset: true}));
          },
  
          // Determine if the model has changed since the last `"change"` event.
          // If you specify an attribute name, determine if that attribute has changed.
          hasChanged: function(attr) {
            if (attr == null) return !isEmptyObject(this.changed);
            return this.changed[attr] !== undefined;
          },
  
          // Return an object containing all the attributes that have changed, or
          // false if there are no changed attributes. Useful for determining what
          // parts of a view need to be updated and/or what attributes need to be
          // persisted to the server. Unset attributes will be set to undefined.
          // You can also pass an attributes object to diff against the model,
          // determining if there *would be* a change.
          changedAttributes: function(diff) {
            if (!diff) return this.hasChanged() ? clone(this.changed) : false;
            var old = this._changing ? this._previousAttributes : this.attributes;
            var changed = {};
            for (var attr in diff) {
              var val = diff[attr];
              if (isEqual(old[attr], val)) continue;
              changed[attr] = val;
            }
            return !isEmptyObject(changed) ? changed : false;
          },
  
          // Get the previous value of an attribute, recorded at the time the last
          // `"change"` event was fired.
          previous: function(attr) {
            if (attr == null || !this._previousAttributes) return null;
            return this._previousAttributes[attr];
          },
  
          // Get all of the attributes of the model at the time of the previous
          // `"change"` event.
          previousAttributes: function() {
            return clone(this._previousAttributes);
          },
  
          // Create a new model with identical attributes to this one.
          clone: function() {
            return new this.constructor(this.attributes);
          },
  
          // A model is new if it has never been saved to the server, and lacks an id.
          isNew: function() {
            return !this.has(this.idAttribute);
          },
  
          // Check if the model is currently in a valid state.
          isValid: function(options) {
            return this._validate({}, mixin({}, options, {validate: true}));
          },
  
          // Run validation against the next complete set of model attributes,
          // returning `true` if all is well. Otherwise, fire an `"invalid"` event.
          _validate: function(attrs, options) {
            if (!options.validate || !this.validate) return true;
            attrs = mixin({}, this.attributes, attrs);
            var error = this.validationError = this.validate(attrs, options) || null;
            if (!error) return true;
            this.trigger('invalid', this, error, mixin(options, {validationError: error}));
            return false;
          }
      });
  
  	return Stateful;
  });
  define('skylark-langx/langx',[
      "./skylark",
      "./arrays",
      "./ArrayStore",
      "./aspect",
      "./async",
      "./Deferred",
      "./Evented",
      "./funcs",
      "./klass",
      "./objects",
      "./Restful",
      "./Stateful",
      "./strings",
      "./types",
      "./Xhr"
  ], function(skylark,arrays,ArrayStore,aspect,async,Deferred,Evented,funcs,klass,objects,Restful,Stateful,strings,types,Xhr) {
      "use strict";
      var toString = {}.toString,
          concat = Array.prototype.concat,
          indexOf = Array.prototype.indexOf,
          slice = Array.prototype.slice,
          filter = Array.prototype.filter,
          mixin = objects.mixin,
          safeMixin = objects.safeMixin,
          isFunction = types.isFunction;
  
  
      function createEvent(type, props) {
          var e = new CustomEvent(type, props);
  
          return safeMixin(e, props);
      }
      
  
      function funcArg(context, arg, idx, payload) {
          return isFunction(arg) ? arg.call(context, idx, payload) : arg;
      }
  
      function getQueryParams(url) {
          var url = url || window.location.href,
              segs = url.split("?"),
              params = {};
  
          if (segs.length > 1) {
              segs[1].split("&").forEach(function(queryParam) {
                  var nv = queryParam.split('=');
                  params[nv[0]] = nv[1];
              });
          }
          return params;
      }
  
  
      function toPixel(value) {
          // style values can be floats, client code may want
          // to round for integer pixels.
          return parseFloat(value) || 0;
      }
  
  
      var _uid = 1;
  
      function uid(obj) {
          return obj._uid || (obj._uid = _uid++);
      }
  
      var idCounter = 0;
      function uniqueId (prefix) {
          var id = ++idCounter + '';
          return prefix ? prefix + id : id;
      }
  
  
      function langx() {
          return langx;
      }
  
      mixin(langx, {
          createEvent : createEvent,
  
          funcArg: funcArg,
  
          getQueryParams: getQueryParams,
  
          toPixel: toPixel,
  
          uid: uid,
  
          uniqueId: uniqueId,
  
          URL: typeof window !== "undefined" ? window.URL || window.webkitURL : null
  
      });
  
  
      mixin(langx, arrays,aspect,funcs,objects,strings,types,{
          ArrayStore : ArrayStore,
  
          async : async,
          
          Deferred: Deferred,
  
          Evented: Evented,
  
          klass : klass,
  
          Restful: Restful,
          
          Stateful: Stateful,
  
          Xhr: Xhr
  
      });
  
      return skylark.langx = langx;
  });
  /**
   * skylark-router - An Elegant HTML5 Routing Framework.
   * @author Hudaokeji Co.,Ltd
   * @version v0.9.6-beta
   * @link www.skylarkjs.org
   * @license MIT
   */
  define('skylark-router/router',[
      "skylark-langx/skylark",
      "skylark-langx/langx"
  ], function(skylark, langx) {
  
      var _curCtx,
          _prevCtx,
          _baseUrl,
          _homePath,
          _routes = {},
          _cache = {},
          _hub = new langx.Evented();
  
      function createEvent(type,props) {
          var e = new CustomEvent(type,props);
          return langx.safeMixin(e, props);
      }
  
      var Route = langx.Evented.inherit({
          klassName: "Route",
          init: function(name, setting) {
              setting = langx.mixin({}, setting);
              var pathto = setting.pathto || "",
                  pattern = pathto,
                  paramNames = pattern.match(/\:([a-zA-Z0-9_]+)/g);
              if (paramNames !== null) {
                  paramNames = paramNames.map(function(paramName) {
                      return paramName.substring(1);
                  });
                  pattern = pattern.replace(/\:([a-zA-Z0-9_]+)/g, '(.*?)');
              } else {
                  paramNames = [];
              }
              if (pattern === "*") {
                  pattern = "(.*)";
              } else {
                  pattern = pattern.replace("/", "\\/");
              }
  
              this._setting = setting;
              this.name = name;
              this.pathto = pathto;
              this.paramNames = paramNames;
              this.params = pattern;
              this.regex = new RegExp("^" + pattern + "$", "");
  
              var self = this;
              ["entering", "entered", "exiting", "exited"].forEach(function(eventName) {
                  if (langx.isFunction(setting[eventName])) {
                      self.on(eventName, setting[eventName]);
                  }
              });
          },
  
          enter: function(ctx,query) {
              if (query) {
                  var r = this._entering(ctx),
                      self = this;
  
                  return langx.Deferred.when(r).then(function(){
                      var e = createEvent("entering", {
                          route: self,
                          result: true
                      });
  
                      self.trigger(e);
  
                      return e.result;
                  });
              } else {
                  this._entered(ctx);
  
                  this.trigger(createEvent("entered", langx.safeMixin({
                      route: this
                  }, ctx)));
                  return this;
              }
          },
  
          exit: function(ctx, query) {
              if (query) {
                  var ok = this._exiting(ctx);
                  if (!ok) {
                      return false;
                  }
  
                  var e = createEvent("exiting", {
                      route: this,
                      result: true
                  });
  
                  this.trigger(e);
  
                  return e.result;
              } else {
                  this._exited(ctx);
                  this.trigger(createEvent("exited", langx.safeMixin({
                      route: this
                  }, ctx)));
  
                  return this;
              }
          },
  
          match: function(path) {
              var names = this.paramNames,
                  x = path.indexOf('?'),
                  path = ~x ? path.slice(0, x) : decodeURIComponent(path),
                  m = this.regex.exec(path);
  
              if (!m) {
                  return false
              };
  
              var params = {};
              for (var i = 1, len = m.length; i < len; ++i) {
                  var name = names[i - 1],
                      val = decodeURIComponent(m[i]);
                  params[name] = val;
              }
  
              return params;
          },
  
          path: function(params) {
              var path = this.pathto;
              if (params) {
                  path = path.replace(/:([a-zA-Z0-9_]+)/g, function(match, paramName) {
                      return params[paramName];
                  });
              }
              return path;
          },
  
          _entering: function(ctx) {
              return true;
          },
          _entered: function(ctx) {
              return true;
          },
          _exiting: function(ctx) {
              return true;
          },
          _exited: function(ctx) {
              return true;
          },
      });
  
      function current() {
          return _curCtx;
      }
  
      // refresh the current route
      function dispatch(ctx) {
  
          if (_curCtx) {
              var ret = _curCtx.route.exit({
                  path: _curCtx.path,
                  params: _curCtx.params
              }, true);
              if (!ret) {
                  return;
              }
          }
  
          _prevCtx = _curCtx;
          _curCtx = ctx;
          if (!_curCtx.route) {
              var m = map(_curCtx.path);
              _curCtx.route = m.route;
              _curCtx.params = m.params;
          }
  
          var r = _curCtx.route.enter({
              force: _curCtx.force,
              path: _curCtx.path,
              params: _curCtx.params
          },true);
  
          langx.Deferred.when(r).then(function() {
              _hub.trigger(createEvent("routing", {
                  current: _curCtx,
                  previous: _prevCtx
              }));
  
              _curCtx.route.enter({
                  path: _curCtx.path,
                  params: _curCtx.params
              },false);
  
              if (_prevCtx) {
                  _prevCtx.route.exit({
                      path: _prevCtx.path,
                      params: _prevCtx.params
                  }, false);
              }
  
              _hub.trigger(createEvent("routed", {
                  current: _curCtx,
                  previous: _prevCtx
              }));
          });
      }
  
      function go(path, force) {
          if (!force && _curCtx && _curCtx.path == path) {
              return false;
          }
          var ctx = map(path);
          if (ctx) {
              ctx.path = path;
  
              if (router.useHistoryApi) {
                  var state = {
                      force: force,
                      path: path
                  }
  
                  window.history.pushState(state, document.title, (_baseUrl + path).replace("//", "/"));
                  window.dispatchEvent(createEvent("popstate", {
                      state: state
                  }));
              } else if (router.useHashbang) {
                  var newHash = "#!" + path;
                  if (window.location.hash !== newHash) {
                      window.location.hash = newHash;
                  } else {
                      dispatch(ctx);
                  };
              } else {
                  dispatch(ctx);
              }
          }
          return true;
      }
  
      function map(path, noCache) {
          var finded = false;
          if (!noCache) {
              finded = _cache[path];
              if (finded) {
                  return finded;
              }
          }
          langx.each(_routes, function(name, route) {
              var ret = route.match(path);
              if (ret) {
                  finded = {
                      route: route,
                      params: ret
                  }
                  return false;
              }
              return true;
          });
          if (finded && !noCache) {
              _cache[path] = finded;
          }
          return finded;
      }
  
      function path(routeName, params) {
          var route = _routes[routeName],
              path;
          if (route) {
              path = route.path(params);
          }
          return path;
      }
  
      function previous() {
          return _prevCtx;
      }
  
      function baseUrl(path) {
          if (langx.isDefined(path)) {
              _baseUrl = path;
              return this;
          } else {
              return _baseUrl;
          }
      }
  
      function hub(){
          return _hub;
      }
  
      function homePath(path) {
          if (langx.isDefined(path)) {
              _homePath = path;
              return this;
          } else {
              return _homePath;
          }
      }
  
      function route(name, setting) {
          if (langx.isDefined(setting)) {
              var settings = {};
              settings[name] = setting;
              routes(settings);
              return this;
          } else {
              return _routes[name];
          }
      }
  
      function routes(settings) {
          if (!langx.isDefined(settings)) {
              return langx.mixin({}, _routes);
          } else {
              for (var name in settings) {
                  _routes[name] = new router.Route(name, settings[name]);
              }
          }
      }
  
      //starts routing urls
      function start() {
          if (router.useHashbang == null && router.useHistoryApi == null) {
              if (window.location.host  && window.history.pushState) {
                  //web access
                  router.useHistoryApi = true;
              } else {
                  // local access
                  router.useHashbang = true;
              }
          }
  
          var initPath = "";
  
          if (router.useHistoryApi) {
              initPath = window.location.pathname;
              if (_baseUrl === undefined) {
                  _baseUrl = initPath.replace(/\/$/, "");
              }
              initPath = initPath.replace(_baseUrl, "") || _homePath || "/";
          } else if (router.useHashbang) {
              initPath = window.location.hash.replace("#!", "") || _homePath || "/";
          } else {
              initPath = "/";
          }
  
          if (!initPath.startsWith("/")) {
              initPath = "/" + initPath;
          }
          /*
          eventer.on(document.body, "click", "a[href]", function(e) {
              var elm = e.currentTarget,
                  url = elm.getAttribute("href");
  
              if (url == "#") {
                  return;
              }
              if (url && langx.isSameOrigin(elm.href)) {
                  if (url.indexOf(_baseUrl) === 0) {
                      url = url.substr(_baseUrl.length);
                      eventer.stop(e);
                      url = url.replace('#!', '');
                      go(url);
                  }
              }
          });
          */
          if (router.useHistoryApi) {
              window.addEventListener("popstate", function(e) {
                  if(e.state) dispatch(e.state);
                  e.preventDefault();
              });
          } else if (router.useHashbang) {
              window.addEventListener("hashchange", function(e) {
                  dispatch({
                      path: window.location.hash.replace(/^#!/, "")
                  });
                  e.preventDefault();
              });
          }
  
          go(initPath);
      }
  
      var router = function() {
          return router;
      };
  
      langx.mixin(router, {
          "Route": Route,
  
          // Current path being processed
          "current": current,
  
          // Changes the current path
          "go": go,
  
          "map": map,
  
          "hub": hub,
  
          "off": function() {
              _hub.off.apply(_hub, arguments);
          },
  
          "on": function() {
              _hub.on.apply(_hub, arguments);
          },
  
          "one": function() {
              _hub.one.apply(_hub, arguments);
          },
  
          // Returns the path of the named route
          "path": path,
  
          "previous": previous,
  
          "baseUrl": baseUrl,
  
          "homePath": homePath,
  
          "route": route,
  
          "routes": routes,
  
          //starts routing urls
          "start": start,
  
          "trigger": function(e) {
              _hub.trigger(e);
              return this;
          },
  
          "useHistoryApi": null,
          "useHashbang": null
      });
  
      return skylark.router = router;
  });
  
  define('skylarkjs/router',[
      "skylark-router/router"
  ], function(router) {
      return router;
  });
  
  define('skylark-spa/spa',[
      "skylark-langx/skylark",
      "skylark-langx/langx",
      "skylark-router/router"
  ], function(skylark, langx, router) {
      var Deferred = langx.Deferred;
  
      function createEvent(type, props) {
          var e = new CustomEvent(type, props);
          return langx.safeMixin(e, props);
      }
  
      var Route = router.Route = router.Route.inherit({
          klassName: "SpaRoute",
  
          init: function(name, setting) {
              this.overrided(name, setting);
              this.content = setting.content;
              this.forceRefresh = setting.forceRefresh;
              this.data = setting.data;
              //this.lazy = !!setting.lazy;
              var self = this;
              ["preparing", "rendering", "rendered"].forEach(function(eventName) {
                  if (langx.isFunction(setting[eventName])) {
                      self.on(eventName, setting[eventName]);
                  }
              });
          },
  
          _entering: function(ctx) {
              if (this.forceRefresh || ctx.force || !this._prepared) {
                  return this.prepare();
              }
              return this;
          },
  
          getConfigData: function(key) {
              return key ? this.data[key] : this.data;
          },
  
          getNamedValue: function() {
              return window.location.pathname.match(this.regex);
          },
  
          prepare: function() {
              var d = new Deferred(),
                  setting = this._setting,
                  controllerSetting = setting.controller,
                  controller = this.controller,
  
                  self = this,
                  content = setting.content,
                  contentPath = setting.contentPath;
  
              require([controllerSetting.type], function(type) {
                  controller = self.controller = new type(controllerSetting);
                  d.resolve();
              });
  
              return d.then(function() {
                  var e = createEvent("preparing", {
                      route: self,
                      result: true
                  });
                  self.trigger(e);
                  return Deferred.when(e.result).then(function() {
                      self._prepared = true;
                  });
              });
          },
  
          render: function(ctx) {
              var e = createEvent("rendering", {
                  route: this,
                  context: ctx,
                  content: this.content
              });
              this.trigger(e);
              return e.content;
          },
  
          trigger: function(e) {
              var controller = this.controller;
              if (controller) {
                  return controller.perform(e);
              } else {
                  return this.overrided(e);
              }
          }
      });
  
      var RouteController = langx.Evented.inherit({
          klassName: "SpaRouteController",
  
          init: function(route, setting) {
              setting = setting || {};
              this.content = setting.content;
              this.data = setting.data;
          },
  
          getConfigData: function(key) {
              return key ? this.data[key] : this.data;
          },
  
          perform: function(e) {
              var eventName = e.type;
              if (this[eventName]) {
                  return this[eventName].call(this, e);
              }
  
          }
      });
  
      var Page = langx.Evented.inherit({
          klassName: "SpaPage",
  
          init: function(params) {
              params = langx.mixin({
                  "routeViewer": "body"
              }, params);
  
              this._params = params;
              this._rvc = document.querySelector(params.routeViewer);
              this._router = router;
  
              router.on("routed", langx.proxy(this, "refresh"));
          },
  
          prepare: function() {
  
          },
  
          //Refreshes the route
          refresh: function() {
              var curCtx = router.current(),
                  prevCtx = router.previous();
              var content = curCtx.route.render(curCtx);
              if (content===undefined || content===null) {
                  return;
              }
              if (langx.isString(content)) {
                  this._rvc.innerHTML = content;
              } else {
                  this._rvc.innerHTML = "";
                  this._rvc.appendChild(content);
              }
              curCtx.route.trigger(createEvent("rendered", {
                  route: curCtx.route,
                  content: content
              }));
          }
      });
  
      var Plugin = langx.Evented.inherit({
          klassName: "SpaPlugin",
  
          init: function(name, setting) {
              this.name = name;
  
              if (langx.isString(setting.hookers)) {
                  setting.hookers = setting.hookers.split(" ");
              }
              this._setting = setting;
          },
  
          isHooked: function(eventName) {
              var hookers = this._setting.hookers || [];
              return hookers.indexOf(eventName) > -1;
          },
  
          prepare: function() {
              var d = new Deferred(),
                  setting = this._setting,
                  controllerSetting = setting.controller,
                  controller = this.controller,
                  self = this;
              require([controllerSetting.type], function(type) {
                  controller = self.controller = new type(controllerSetting);
                  router.on(setting.hookers, {
                      plugin: self
                  }, langx.proxy(controller.perform, controller));
                  d.resolve();
              });
              return d.then(function() {
                  var e = createEvent("preparing", {
                      plugin: self,
                      result: true
                  });
                  self.trigger(e);
                  return Deferred.when(e.result).then(function() {
                      self._prepared = true;
                  });
              });
          },
  
          trigger: function(e) {
              var controller = this.controller;
              if (controller) {
                  return controller.perform(e);
              } else {
                  return this.overrided(e);
              }
          }
      });
  
      var PluginController = langx.Evented.inherit({
          klassName: "SpaPluginController",
  
          init: function(plugin) {
              this.plugin = plugin;
          },
  
          perform: function(e) {
              var eventName = e.type;
              if (this[eventName]) {
                  return this[eventName].call(this, e);
              }
  
          }
      });
  
      var Application = langx.Evented.inherit({
          klassName: "SpaApplication",
  
          init: function(config) {
              if (app) {
                  return app;
              }
              var plugins = this._plugins = {};
  
              config = this._config = langx.mixin({
                  plugins: {}
              }, config, true);
  
              langx.each(config.plugins, function(pluginName, setting) {
                  plugins[pluginName] = new Plugin(pluginName, setting);
              });
  
              router.routes(config.routes);
  
              this._router = router;
  
              this._page = new spa.Page(config.page);
  
              document.title = config.title;
              var baseUrl = config.baseUrl;
              if (baseUrl === undefined) {
                  baseUrl = config.baseUrl = (new langx.URL(document.baseURI)).pathname;
              }
              router.baseUrl(baseUrl);
  
              if (config.homePath) {
                  router.homePath(config.homePath);
              }
  
              app = this;
          },
  
          baseUrl : function() {
              return router.baseUrl();
          },
  
          getConfig: function(key) {
              return key ? this._config[key] : this._config;
          },
  
          go: function(path, force) {
              router.go(path, force);
              return this;
          },
  
          page: function() {
              return this._page;
          },
  
          prepare: function() {
              if (this._prepared) {
                  return Deferred.resolve();
              }
              var self = this;
  
              var promises0 = langx.map(this._plugins, function(plugin, name) {
                  if (plugin.isHooked("starting")) {
                      return plugin.prepare();
                  }
              });
  
              return Deferred.all(promises0).then(function() {
                  router.trigger(createEvent("starting", {
                      spa: self
                  }));
                  var promises1 = langx.map(router.routes(), function(route, name) {
                          if (route.lazy === false) {
                              return route.prepare();
                          }
                      }),
                      promises2 = langx.map(self._plugins, function(plugin, name) {
                          if (!plugin.isHooked("starting")) {
                              return plugin.prepare();
                          }
                      });
  
  
                  return Deferred.all(promises1.concat(promises2)).then(function() {
                      self._prepared = true;
                  });
              });
          },
  
          run: function() {
              this._router.start();
              router.trigger(createEvent("started", {
                  spa: this
              }));
          }
      });
  
      var app;
      var spa = function(config) {
          if (!app) {
              window[config.name || "app"] = app = new spa.Application(config);
          }
  
          return app;
      }
  
      langx.mixin(spa, {
          "Application": Application,
  
          "Page": Page,
  
          "Plugin": Plugin,
          "PluginController": PluginController,
  
          "Route": Route,
          "RouteController": RouteController
  
      });
  
      return skylark.spa = spa;
  });
  
  define('skylarkjs/spa',[
      "skylark-spa/spa"
  ], function(spa) {
      return spa;
  });
  
  define('skylarkjs/langx',[
      "skylark-langx/langx"
  ], function(langx) {
      return langx;
  });
  
  define('skylarkjs/core',[
      "./skylark",
      "./router",
      "./spa",
      "./langx"
  ], function(skylark) {
      return skylark;
  })
  ;
  define('skylark-utils/langx',[
      "skylark-langx/langx"
  ], function(langx) {
      return langx;
  });
  
  define('skylark-utils/browser',[
      "./skylark",
      "./langx"
  ], function(skylark,langx) {
      var checkedCssProperties = {
          "transitionproperty": "TransitionProperty",
      };
  
      var css3PropPrefix = "",
          css3StylePrefix = "",
          css3EventPrefix = "",
  
          cssStyles = {},
          cssProps = {},
  
          vendorPrefix,
          vendorPrefixRE,
          vendorPrefixesRE = /^(Webkit|webkit|O|Moz|moz|ms)(.*)$/,
  
          document = window.document,
          testEl = document.createElement("div"),
  
          matchesSelector = testEl.webkitMatchesSelector ||
                            testEl.mozMatchesSelector ||
                            testEl.oMatchesSelector ||
                            testEl.matchesSelector,
  
          requestFullScreen = testEl.requestFullscreen || 
                              testEl.webkitRequestFullscreen || 
                              testEl.mozRequestFullScreen || 
                              testEl.msRequestFullscreen,
  
          exitFullScreen =  document.exitFullscreen ||
                            document.webkitCancelFullScreen ||
                            document.mozCancelFullScreen ||
                            document.msExitFullscreen,
  
          testStyle = testEl.style;
  
      for (var name in testStyle) {
          var matched = name.match(vendorPrefixRE || vendorPrefixesRE);
          if (matched) {
              if (!vendorPrefixRE) {
                  vendorPrefix = matched[1];
                  vendorPrefixRE = new RegExp("^(" + vendorPrefix + ")(.*)$");
  
                  css3StylePrefix = vendorPrefix;
                  css3PropPrefix = '-' + vendorPrefix.toLowerCase() + '-';
                  css3EventPrefix = vendorPrefix.toLowerCase();
              }
  
              cssStyles[langx.lowerFirst(matched[2])] = name;
              var cssPropName = langx.dasherize(matched[2]);
              cssProps[cssPropName] = css3PropPrefix + cssPropName;
  
          }
      }
  
  
      function normalizeCssEvent(name) {
          return css3EventPrefix ? css3EventPrefix + name : name.toLowerCase();
      }
  
      function normalizeCssProperty(name) {
          return cssProps[name] || name;
      }
  
      function normalizeStyleProperty(name) {
          return cssStyles[name] || name;
      }
  
      function browser() {
          return browser;
      }
  
      langx.mixin(browser, {
          css3PropPrefix: css3PropPrefix,
  
          isIE : !!/msie/i.exec( window.navigator.userAgent ),
  
          normalizeStyleProperty: normalizeStyleProperty,
  
          normalizeCssProperty: normalizeCssProperty,
  
          normalizeCssEvent: normalizeCssEvent,
  
          matchesSelector: matchesSelector,
  
          requestFullScreen : requestFullScreen,
  
          exitFullscreen : requestFullScreen,
  
          location: function() {
              return window.location;
          },
  
          support : {
  
          }
  
      });
  
      testEl = null;
  
      return skylark.browser = browser;
  });
  
  define('skylarkjs/browser',[
      "skylark-utils/browser"
  ], function(browser) {
      return browser;
  });
  
  define('skylark-utils/styler',[
      "./skylark",
      "./langx"
  ], function(skylark, langx) {
      var every = Array.prototype.every,
          forEach = Array.prototype.forEach,
          camelCase = langx.camelCase,
          dasherize = langx.dasherize;
  
      function maybeAddPx(name, value) {
          return (typeof value == "number" && !cssNumber[dasherize(name)]) ? value + "px" : value
      }
  
      var cssNumber = {
              'column-count': 1,
              'columns': 1,
              'font-weight': 1,
              'line-height': 1,
              'opacity': 1,
              'z-index': 1,
              'zoom': 1
          },
          classReCache = {
  
          };
  
      function classRE(name) {
          return name in classReCache ?
              classReCache[name] : (classReCache[name] = new RegExp('(^|\\s)' + name + '(\\s|$)'));
      }
  
      // access className property while respecting SVGAnimatedString
      /*
       * Adds the specified class(es) to each element in the set of matched elements.
       * @param {HTMLElement} node
       * @param {String} value
       */
      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)
      }
  
      function disabled(elm, value ) {
          if (arguments.length < 2) {
              return !!this.dom.disabled;
          }
  
          elm.disabled = value;
  
          return this;
      }
  
      var elementDisplay = {};
  
      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]
      }
      /*
       * Display the matched elements.
       * @param {HTMLElement} elm
       */
      function show(elm) {
          styler.css(elm, "display", "");
          if (styler.css(elm, "display") == "none") {
              styler.css(elm, "display", defaultDisplay(elm.nodeName));
          }
          return this;
      }
  
      function isInvisible(elm) {
          return styler.css(elm, "display") == "none" || styler.css(elm, "opacity") == 0;
      }
  
      /*
       * Hide the matched elements.
       * @param {HTMLElement} elm
       */
      function hide(elm) {
          styler.css(elm, "display", "none");
          return this;
      }
  
      /*
       * Adds the specified class(es) to each element in the set of matched elements.
       * @param {HTMLElement} elm
       * @param {String} name
       */
      function addClass(elm, name) {
          if (!name) return this
          var cls = className(elm),
              names;
          if (langx.isString(name)) {
              names = name.split(/\s+/g);
          } else {
              names = name;
          }
          names.forEach(function(klass) {
              var re = classRE(klass);
              if (!cls.match(re)) {
                  cls += (cls ? " " : "") + klass;
              }
          });
  
          className(elm, cls);
  
          return this;
      }
      /*
       * Get the value of a computed style property for the first element in the set of matched elements or set one or more CSS properties for every matched element.
       * @param {HTMLElement} elm
       * @param {String} property
       * @param {Any} value
       */
      function css(elm, property, value) {
          if (arguments.length < 3) {
              var computedStyle,
                  computedStyle = getComputedStyle(elm, '')
              if (langx.isString(property)) {
                  return elm.style[camelCase(property)] || computedStyle.getPropertyValue(dasherize(property))
              } else if (langx.isArrayLike(property)) {
                  var props = {}
                  forEach.call(property, function(prop) {
                      props[prop] = (elm.style[camelCase(prop)] || computedStyle.getPropertyValue(dasherize(prop)))
                  })
                  return props
              }
          }
  
          var css = '';
          if (typeof(property) == 'string') {
              if (!value && value !== 0) {
                  elm.style.removeProperty(dasherize(property));
              } else {
                  css = dasherize(property) + ":" + maybeAddPx(property, value)
              }
          } else {
              for (key in property) {
                  if (property[key] === undefined) {
                      continue;
                  }
                  if (!property[key] && property[key] !== 0) {
                      elm.style.removeProperty(dasherize(key));
                  } else {
                      css += dasherize(key) + ':' + maybeAddPx(key, property[key]) + ';'
                  }
              }
          }
  
          elm.style.cssText += ';' + css;
          return this;
      }
  
      /*
       * Determine whether any of the matched elements are assigned the given class.
       * @param {HTMLElement} elm
       * @param {String} name
       */
      function hasClass(elm, name) {
          var re = classRE(name);
          return elm.className && elm.className.match(re);
      }
  
      /*
       * Remove a single class, multiple classes, or all classes from each element in the set of matched elements.
       * @param {HTMLElement} elm
       * @param {String} name
       */
      function removeClass(elm, name) {
          if (name) {
              var cls = className(elm),
                  names;
  
              if (langx.isString(name)) {
                  names = name.split(/\s+/g);
              } else {
                  names = name;
              }
  
              names.forEach(function(klass) {
                  var re = classRE(klass);
                  if (cls.match(re)) {
                      cls = cls.replace(re, " ");
                  }
              });
  
              className(elm, cls.trim());
          } else {
              className(elm, "");
          }
  
          return this;
      }
  
      /*
       * Add or remove one or more classes from the specified element.
       * @param {HTMLElement} elm
       * @param {String} name
       * @param {} when
       */
      function toggleClass(elm, name, when) {
          var self = this;
          name.split(/\s+/g).forEach(function(klass) {
              if (when === undefined) {
                  when = !self.hasClass(elm, klass);
              }
              if (when) {
                  self.addClass(elm, klass);
              } else {
                  self.removeClass(elm, klass)
              }
          });
  
          return self;
      }
  
      var styler = function() {
          return styler;
      };
  
      langx.mixin(styler, {
          autocssfix: false,
          cssHooks: {
  
          },
  
          addClass: addClass,
          className: className,
          css: css,
          disabled : disabled,        
          hasClass: hasClass,
          hide: hide,
          isInvisible: isInvisible,
          removeClass: removeClass,
          show: show,
          toggleClass: toggleClass
      });
  
      return skylark.styler = styler;
  });
  define('skylark-utils/noder',[
      "./skylark",
      "./langx",
      "./browser",
      "./styler"
  ], function(skylark, langx, browser, styler) {
      var isIE = !!navigator.userAgent.match(/Trident/g) || !!navigator.userAgent.match(/MSIE/g),
          fragmentRE = /^\s*<(\w+|!)[^>]*>/,
          singleTagRE = /^<(\w+)\s*\/?>(?:<\/\1>|)$/,
          div = document.createElement("div"),
          table = document.createElement('table'),
          tableBody = document.createElement('tbody'),
          tableRow = document.createElement('tr'),
          containers = {
              'tr': tableBody,
              'tbody': table,
              'thead': table,
              'tfoot': table,
              'td': tableRow,
              'th': tableRow,
              '*': div
          },
          rootNodeRE = /^(?:body|html)$/i,
          map = Array.prototype.map,
          slice = Array.prototype.slice;
  
      function ensureNodes(nodes, copyByClone) {
          if (!langx.isArrayLike(nodes)) {
              nodes = [nodes];
          }
          if (copyByClone) {
              nodes = map.call(nodes, function(node) {
                  return node.cloneNode(true);
              });
          }
          return langx.flatten(nodes);
      }
  
      function nodeName(elm, chkName) {
          var name = elm.nodeName && elm.nodeName.toLowerCase();
          if (chkName !== undefined) {
              return name === chkName.toLowerCase();
          }
          return name;
      };
  
      function after(node, placing, copyByClone) {
          var refNode = node,
              parent = refNode.parentNode;
          if (parent) {
              var nodes = ensureNodes(placing, copyByClone),
                  refNode = refNode.nextSibling;
  
              for (var i = 0; i < nodes.length; i++) {
                  if (refNode) {
                      parent.insertBefore(nodes[i], refNode);
                  } else {
                      parent.appendChild(nodes[i]);
                  }
              }
          }
          return this;
      }
  
      function append(node, placing, copyByClone) {
          var parentNode = node,
              nodes = ensureNodes(placing, copyByClone);
          for (var i = 0; i < nodes.length; i++) {
              parentNode.appendChild(nodes[i]);
          }
          return this;
      }
  
      function before(node, placing, copyByClone) {
          var refNode = node,
              parent = refNode.parentNode;
          if (parent) {
              var nodes = ensureNodes(placing, copyByClone);
              for (var i = 0; i < nodes.length; i++) {
                  parent.insertBefore(nodes[i], refNode);
              }
          }
          return this;
      }
      /*   
       * Get the children of the specified node, including text and comment nodes.
       * @param {HTMLElement} elm
       */
      function contents(elm) {
          if (nodeName(elm, "iframe")) {
              return elm.contentDocument;
          }
          return elm.childNodes;
      }
  
      /*   
       * Create a element and set attributes on it.
       * @param {HTMLElement} tag
       * @param {props} props
       * @param } parent
       */
      function createElement(tag, props, parent) {
          var node = document.createElement(tag);
          if (props) {
              for (var name in props) {
                  node.setAttribute(name, props[name]);
              }
          }
          if (parent) {
              append(parent, node);
          }
          return node;
      }
  
      /*   
       * Create a DocumentFragment from the HTML fragment.
       * @param {String} html
       */
      function createFragment(html) {
          // A special case optimization for a single tag
          html = langx.trim(html);
          if (singleTagRE.test(html)) {
              return [createElement(RegExp.$1)];
          }
  
          var name = fragmentRE.test(html) && RegExp.$1
          if (!(name in containers)) {
              name = "*"
          }
          var container = containers[name];
          container.innerHTML = "" + html;
          dom = slice.call(container.childNodes);
  
          dom.forEach(function(node) {
              container.removeChild(node);
          })
  
          return dom;
      }
  
      /*   
       * Create a deep copy of the set of matched elements.
       * @param {HTMLElement} node
       * @param {Boolean} deep
       */
      function clone(node, deep) {
          var self = this,
              clone;
  
          // TODO: Add feature detection here in the future
          if (!isIE || node.nodeType !== 1 || deep) {
              return node.cloneNode(deep);
          }
  
          // Make a HTML5 safe shallow copy
          if (!deep) {
              clone = document.createElement(node.nodeName);
  
              // Copy attribs
              each(self.getAttribs(node), function(attr) {
                  self.setAttrib(clone, attr.nodeName, self.getAttrib(node, attr.nodeName));
              });
  
              return clone;
          }
      }
  
      /*   
       * Check to see if a dom node is a descendant of another dom node .
       * @param {String} node
       * @param {Node} child
       */
      function contains(node, child) {
          return isChildOf(child, node);
      }
  
      /*   
       * Create a new Text node.
       * @param {String} text
       * @param {Node} child
       */
      function createTextNode(text) {
          return document.createTextNode(text);
      }
  
      /*   
       * Get the current document object.
       */
      function doc() {
          return document;
      }
  
      /*   
       * Remove all child nodes of the set of matched elements from the DOM.
       * @param {Object} node
       */
      function empty(node) {
          while (node.hasChildNodes()) {
              var child = node.firstChild;
              node.removeChild(child);
          }
          return this;
      }
  
      var fulledEl = null;
  
      function fullScreen(el) {
          if (el === false) {
              browser.exitFullScreen.apply(document);
          } else if (el) {
              browser.requestFullScreen.apply(el);
              fulledEl = el;
          } else {
              return (
                  document.fullscreenElement ||
                  document.webkitFullscreenElement ||
                  document.mozFullScreenElement ||
                  document.msFullscreenElement
              )
          }
      }
  
     var rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi;
   
      /*   
       * Get the HTML contents of the first element in the set of matched elements.
       * @param {HTMLElement} node
       * @param {String} html
       */
      function html(node, html) {
          if (html === undefined) {
              return node.innerHTML;
          } else {
              this.empty(node);
              html = html || "";
              if (langx.isString(html)) {
                  html = html.replace( rxhtmlTag, "<$1></$2>" );
              }
              if (langx.isString(html) || langx.isNumber(html)) {               
                  node.innerHTML = html;
              } else if (langx.isArrayLike(html)) {
                  for (var i = 0; i < html.length; i++) {
                      node.appendChild(html[i]);
                  }
              } else {
                  node.appendChild(html);
              }
          }
      }
  
  
      /*   
       * Check to see if a dom node is a descendant of another dom node.
       * @param {Node} node
       * @param {Node} parent
       * @param {Node} directly
       */
      function isChildOf(node, parent, directly) {
          if (directly) {
              return node.parentNode === parent;
          }
          if (document.documentElement.contains) {
              return parent.contains(node);
          }
          while (node) {
              if (parent === node) {
                  return true;
              }
  
              node = node.parentNode;
          }
  
          return false;
      }
  
      /*   
       * Check to see if a dom node is a descendant of another dom node.
       * @param {Node} node
       * @param {Node} parent
       * @param {Node} directly
       */
      function isDoc(node) {
          return node != null && node.nodeType == node.DOCUMENT_NODE
      }
  
      /*   
       * Get the owner document object for the specified element.
       * @param {Node} elm
       */
      function ownerDoc(elm) {
          if (!elm) {
              return document;
          }
  
          if (elm.nodeType == 9) {
              return elm;
          }
  
          return elm.ownerDocument;
      }
  
      /*   
       *
       * @param {Node} elm
       */
      function ownerWindow(elm) {
          var doc = ownerDoc(elm);
          return doc.defaultView || doc.parentWindow;
      }
  
      /*   
       * insert one or more nodes as the first children of the specified node.
       * @param {Node} node
       * @param {Node or ArrayLike} placing
       * @param {Boolean Optional} copyByClone
       */
      function prepend(node, placing, copyByClone) {
          var parentNode = node,
              refNode = parentNode.firstChild,
              nodes = ensureNodes(placing, copyByClone);
          for (var i = 0; i < nodes.length; i++) {
              if (refNode) {
                  parentNode.insertBefore(nodes[i], refNode);
              } else {
                  parentNode.appendChild(nodes[i]);
              }
          }
          return this;
      }
  
      /*   
       *
       * @param {Node} elm
       */
      function offsetParent(elm) {
          var parent = elm.offsetParent || document.body;
          while (parent && !rootNodeRE.test(parent.nodeName) && styler.css(parent, "position") == "static") {
              parent = parent.offsetParent;
          }
          return parent;
      }
  
      /*   
       *
       * @param {Node} elm
       * @param {Node} params
       */
      function overlay(elm, params) {
          var overlayDiv = createElement("div", params);
          styler.css(overlayDiv, {
              position: "absolute",
              top: 0,
              left: 0,
              width: "100%",
              height: "100%",
              zIndex: 0x7FFFFFFF,
              opacity: 0.7
          });
          elm.appendChild(overlayDiv);
          return overlayDiv;
  
      }
  
      /*   
       * Remove the set of matched elements from the DOM.
       * @param {Node} node
       */
      function remove(node) {
          if (node && node.parentNode) {
              try {
                  node.parentNode.removeChild(node);
              } catch (e) {
                  console.warn("The node is already removed", e);
              }
          }
          return this;
      }
  
      function removeChild(node,children) {
          if (!langx.isArrayLike(children)) {
              children = [children];
          }
          for (var i=0;i<children.length;i++) {
              node.removeChild(children[i]);
          }
  
          return this;
      }
      /*   
       * Replace an old node with the specified node.
       * @param {Node} node
       * @param {Node} oldNode
       */
      function replace(node, oldNode) {
          oldNode.parentNode.replaceChild(node, oldNode);
          return this;
      }
  
      /*   
       * Replace an old node with the specified node.
       * @param {HTMLElement} elm
       * @param {Node} params
       */
      function throb(elm, params) {
          params = params || {};
          var self = this,
              text = params.text,
              style = params.style,
              time = params.time,
              callback = params.callback,
              timer,
              throbber = this.createElement("div", {
                  className: params.className || "throbber",
                  style: style
              }),
              _overlay = overlay(throbber, {
                  className: 'overlay fade'
              }),
              throb = this.createElement("div", {
                  className: "throb"
              }),
              textNode = this.createTextNode(text || ""),
              remove = function() {
                  if (timer) {
                      clearTimeout(timer);
                      timer = null;
                  }
                  if (throbber) {
                      self.remove(throbber);
                      throbber = null;
                  }
              },
              update = function(params) {
                  if (params && params.text && throbber) {
                      textNode.nodeValue = params.text;
                  }
              };
          throb.appendChild(textNode);
          throbber.appendChild(throb);
          elm.appendChild(throbber);
          var end = function() {
              remove();
              if (callback) callback();
          };
          if (time) {
              timer = setTimeout(end, time);
          }
  
          return {
              remove: remove,
              update: update
          };
      }
  
      /*   
       * traverse the specified node and its descendants, perform the callback function on each
       * @param {Node} node
       * @param {Function} fn
       */
      function traverse(node, fn) {
          fn(node)
          for (var i = 0, len = node.childNodes.length; i < len; i++) {
              traverse(node.childNodes[i], fn);
          }
          return this;
      }
  
      /*   
       *
       * @param {Node} node
       */
      function reverse(node) {
          var firstChild = node.firstChild;
          for (var i = node.children.length - 1; i > 0; i--) {
              if (i > 0) {
                  var child = node.children[i];
                  node.insertBefore(child, firstChild);
              }
          }
      }
  
      /*   
       * Wrap an HTML structure around each element in the set of matched elements.
       * @param {Node} node
       * @param {Node} wrapperNode
       */
      function wrapper(node, wrapperNode) {
          if (langx.isString(wrapperNode)) {
              wrapperNode = this.createFragment(wrapperNode).firstChild;
          }
          node.parentNode.insertBefore(wrapperNode, node);
          wrapperNode.appendChild(node);
      }
  
      /*   
       * Wrap an HTML structure around the content of each element in the set of matched
       * @param {Node} node
       * @param {Node} wrapperNode
       */
      function wrapperInner(node, wrapperNode) {
          var childNodes = slice.call(node.childNodes);
          node.appendChild(wrapperNode);
          for (var i = 0; i < childNodes.length; i++) {
              wrapperNode.appendChild(childNodes[i]);
          }
          return this;
      }
  
      /*   
       * Remove the parents of the set of matched elements from the DOM, leaving the matched
       * @param {Node} node
       */
      function unwrap(node) {
          var child, parent = node.parentNode;
          if (parent) {
              if (this.isDoc(parent.parentNode)) return;
              parent.parentNode.insertBefore(node, parent);
          }
      }
  
      function noder() {
          return noder;
      }
  
      langx.mixin(noder, {
          body: function() {
              return document.body;
          },
  
          clone: clone,
          contents: contents,
  
          createElement: createElement,
  
          createFragment: createFragment,
  
          contains: contains,
  
          createTextNode: createTextNode,
  
          doc: doc,
  
          empty: empty,
  
          fullScreen: fullScreen,
  
          html: html,
  
          isChildOf: isChildOf,
  
          isDoc: isDoc,
  
          isWindow: langx.isWindow,
  
          offsetParent: offsetParent,
  
          ownerDoc: ownerDoc,
  
          ownerWindow: ownerWindow,
  
          after: after,
  
          before: before,
  
          prepend: prepend,
  
          append: append,
  
          remove: remove,
  
          removeChild : removeChild,
  
          replace: replace,
  
          throb: throb,
  
          traverse: traverse,
  
          reverse: reverse,
  
          wrapper: wrapper,
  
          wrapperInner: wrapperInner,
  
          unwrap: unwrap
      });
  
      return skylark.noder = noder;
  });
  define('skylark-utils/css',[
      "./skylark",
      "./langx",
      "./noder"
  ], function(skylark, langx, noder) {
  
      var head = document.getElementsByTagName("head")[0],
          count = 0,
          sheetsByUrl = {},
          sheetsById = {},
          defaultSheetId = _createStyleSheet(),
          defaultSheet = sheetsById[defaultSheetId],
          rulesPropName = ("cssRules" in defaultSheet) ? "cssRules" : "rules",
          insertRuleFunc,
          deleteRuleFunc = defaultSheet.deleteRule || defaultSheet.removeRule;
  
      if (defaultSheet.insertRule) {
          var _insertRule = defaultSheet.insertRule;
          insertRuleFunc = function(selector, css, index) {
              _insertRule.call(this, selector + "{" + css + "}", index);
          };
      } else {
          insertRuleFunc = defaultSheet.addRule;
      }
  
      function normalizeSelector(selectorText) {
          var selector = [],
              last, len;
          last = defaultSheet[rulesPropName].length;
          insertRuleFunc.call(defaultSheet, selectorText, ';');
          len = defaultSheet[rulesPropName].length;
          for (var i = len - 1; i >= last; i--) {
              selector.push(_sheet[_rules][i].selectorText);
              deleteRuleFunc.call(defaultSheet, i);
          }
          return selector.reverse().join(', ');
      }
  
      /*
       * create a stylesheet element.
       * @param {Boolean} external
       * @param {Object} options
       * @param {String} [options.media = null]
       */
      function _createStyleSheet(external,options ) {
          var node,
              props = {
                  type : "text/css"
              },
              id = (count++);
  
          options = options || {};
          if (options.media) {
              props.media = options.media;
          }
  
          if (external) {
              node = noder.create("link",langx.mixin(props,{
                  rel  : "stylesheet",
                  async : false
              }));
          } else {
              node = noder.createElement("style",props);
          }
  
          noder.append(head,node);
          sheetsById[id] = {
              id : id,
              node :node
          };
  
          return id;
      }
  
      function createStyleSheet(css,options) {
          if (!options) {
              options = {};
          }
          var sheetId = _createStyleSheet(false,options);
          if (css) {
              addSheetRules(sheetId,css);
          }
  
          return sheetId;
      }
  
      function loadStyleSheet(url, options) {
          var sheet = sheetsByUrl[url];
          if (!sheet) {
              var sheetId = _createStyleSheet(true,options);
  
              sheet = sheetsByUrl[url] = sheetsById[sheetId];
              langx.mixin(sheet,{
                  state: 0, //0:unload,1:loaded,-1:loaderror
                  url : url,
                  deferred : new langx.Deferred()
              });
  
              var node = sheet.node;
  
              startTime = new Date().getTime();
  
              node.onload = function() {
                  sheet.state = 1;
                  sheet.deferred.resolve(sheet.id);
              },
              node.onerror = function(e) {
                  sheet.state = -1;
                  sheet.deferred.reject(e);
              };
  
              node.href = sheet.url;
          }
          return sheet.deferred.promise;
      }
  
      function deleteSheetRule(sheetId, rule) {
          var sheet = sheetsById[sheetId];
          if (langx.isNumber(rule)) {
              deleteRuleFunc.call(sheet, rule);
          } else {
              langx.each(sheet[rulesPropName], function(i, _rule) {
                  if (rule === _rule) {
                      deleteRuleFunc.call(sheet, i);
                      return false;
                  }
              });
          }
          return this;
      }
  
      function deleteRule(rule) {
          deleteSheetRule(defaultSheetId, rule);
          return this;
      }
  
      function removeStyleSheet(sheetId) {
          if (sheetId === defaultSheetId) {
              throw new Error("The default stylesheet can not be deleted");
          }
          var sheet = sheetsById[sheetId];
          delete sheetsById[sheetId];
  
          noder.remove(sheet.node);
          return this;
      }
  
      /*
       * insert a rule to the default stylesheet.
       * @param {String} selector
       * @param {String} css
       * @param {Number} index 
       */
      function insertRule(selector, css, index) {
          return this.insertSheetRule(defaultSheetId, selector, css, index);
      }
  
      /*
       * Add rules to the default stylesheet.
       * @param {Object} rules
       */
      function addRules(rules) {
          return this.addRules(defaultSheetId,rules);
      }
  
      /*
       * insert a rule to the stylesheet specified by sheetId.
       * @param {Number} sheetId  
       * @param {String} selector
       * @param {String} css
       * @param {Number} index 
       */
      function insertSheetRule(sheetId, selector, css, index) {
          if (!selector || !css) {
              return -1;
          }
  
          var sheet = sheetsById[sheetId];
          index = index || sheet[rulesPropName].length;
  
          return insertRuleFunc.call(sheet, selector, css, index);
      }
  
      /*
       * Add  rules to stylesheet.
       * @param {Number} sheetId  
       * @param {Object|String} rules
       * @return this
       * @example insertSheetRules(sheetId,{
       * 
       * });
       */
      function addSheetRules(sheetId,rules) {
          var sheet = sheetsById[sheetId],
              css;
          if (langx.isString(rules)) {
              css = rules;
          } else {
              css = toString(rules);
          }
  
          noder.append(sheet.node,noder.createTextNode(css));
          
          return this;
      }
  
      function isAtRule(str) {
          return str.startsWith("@");
      }
  
      function toString(json){
          var adjust = function(parentName,name,depth) {
              if (parentName) {
                  if (isAtRule(parentName)) {
                      depth += 1;
                  } else {
                      name =  parentName + " " + name;
                  }                
              }
              return {
                  name : name,
                  depth : depth
              }
          };
  
          var strNode = function (name, values, depth) {
              var str = "",
                  atFlg = isAtRule(name);
  
  
              if (isAtRule(name)) {
                  // at rule
                  if (langx.isString(values)) {
                      // an at rule without block
                      // ex: (1) @charset 'utf8';
                      str = css.SPACE.repeat(depth) + name.trim() + " \"" + values.trim() + " \";\n";
                  } else {
                      // an at rule with block, ex :
                      //  @media 'screen' {
                      //  }
                      str += css.SPACE.repeat(depth) + name.trim() + " {\n";
                      str += strNode("",values,depth+1);
                      str += css.SPACE.repeat(depth) + " }\n";
                  }
              } else {
                  // a selector or a property
                  if (langx.isString(values)) {
                      // a css property 
                      // ex : (1) font-color : red;
                      str = css.SPACE.repeat(depth) + name.trim() ;
                      if (atFlg) {
                          str = str +  " \"" + values.trim() + " \";\n";
                      } else {
                          str = str + ': ' + values.trim() + ";\n";
                      }
  
                  } else {
                      // a selector rule 
                      // ex : (1) .class1 : {
                      //            font-color : red;
                      //          }
                      if (langx.isArray(values)) {
                          // array for ordering
                          for (var n =0; n<values.length; n ++) {
                             str +=  strNode(name,values[n],depth);
                          }
                      } else {
                          // plain object
  
                          if (name) {
                              str += css.SPACE.repeat(depth) + name.trim() + " {\n";
  
                              for (var n in values) {
                                  var value =values[n];
                                  if (langx.isString(value)) {
                                      // css property
                                      str += strNode(n,value,depth+1)
                                  }
                              }
  
                              str += css.SPACE.repeat(depth) + "}\n";
                          }
  
                          for (var n in values) {
                              var value =values[n];
                              if (!langx.isString(value)) {
                                  var adjusted = adjust(name,n,depth);
                                  str +=  strNode(adjusted.name,value,adjusted.depth);
                              } 
                          }
  
                      }
                  }
              }   
  
              return str;
          };
  
  
          return strNode("",json,0);
      }
   
  
      function css() {
          return css;
      }
  
      langx.mixin(css, {
          SPACE : "\t",
  
          addRules : addRules,
  
          addSheetRules : addSheetRules,
  
          createStyleSheet: createStyleSheet,
  
          deleteSheetRule : deleteSheetRule,
  
          deleteRule : deleteRule,
  
          insertRule : insertRule,
  
          insertSheetRule : insertSheetRule,
  
          removeStyleSheet : removeStyleSheet,
  
          toString : toString
      });
  
      return skylark.css = css;
  });
  
  define('skylarkjs/css',[
      "skylark-utils/css"
  ], function(css) {
      return css;
  });
  
  define('skylark-utils/finder',[
      "./skylark",
      "./langx",
      "./browser",
      "./noder"
  ], function(skylark, langx, browser, noder, velm) {
      var local = {},
          filter = Array.prototype.filter,
          slice = Array.prototype.slice,
          nativeMatchesSelector = browser.matchesSelector;
  
      /*
      ---
      name: Slick.Parser
      description: Standalone CSS3 Selector parser
      provides: Slick.Parser
      ...
      */
      ;
      (function() {
  
          var parsed,
              separatorIndex,
              combinatorIndex,
              reversed,
              cache = {},
              reverseCache = {},
              reUnescape = /\\/g;
  
          var parse = function(expression, isReversed) {
              if (expression == null) return null;
              if (expression.Slick === true) return expression;
              expression = ('' + expression).replace(/^\s+|\s+$/g, '');
              reversed = !!isReversed;
              var currentCache = (reversed) ? reverseCache : cache;
              if (currentCache[expression]) return currentCache[expression];
              parsed = {
                  Slick: true,
                  expressions: [],
                  raw: expression,
                  reverse: function() {
                      return parse(this.raw, true);
                  }
              };
              separatorIndex = -1;
              while (expression != (expression = expression.replace(regexp, parser)));
              parsed.length = parsed.expressions.length;
              return currentCache[parsed.raw] = (reversed) ? reverse(parsed) : parsed;
          };
  
          var reverseCombinator = function(combinator) {
              if (combinator === '!') return ' ';
              else if (combinator === ' ') return '!';
              else if ((/^!/).test(combinator)) return combinator.replace(/^!/, '');
              else return '!' + combinator;
          };
  
          var reverse = function(expression) {
              var expressions = expression.expressions;
              for (var i = 0; i < expressions.length; i++) {
                  var exp = expressions[i];
                  var last = {
                      parts: [],
                      tag: '*',
                      combinator: reverseCombinator(exp[0].combinator)
                  };
  
                  for (var j = 0; j < exp.length; j++) {
                      var cexp = exp[j];
                      if (!cexp.reverseCombinator) cexp.reverseCombinator = ' ';
                      cexp.combinator = cexp.reverseCombinator;
                      delete cexp.reverseCombinator;
                  }
  
                  exp.reverse().push(last);
              }
              return expression;
          };
  
          var escapeRegExp = (function() {
              // Credit: XRegExp 0.6.1 (c) 2007-2008 Steven Levithan <http://stevenlevithan.com/regex/xregexp/> MIT License
              var from = /(?=[\-\[\]{}()*+?.\\\^$|,#\s])/g,
                  to = '\\';
              return function(string) {
                  return string.replace(from, to)
              }
          }())
  
          var regexp = new RegExp(
              "^(?:\\s*(,)\\s*|\\s*(<combinator>+)\\s*|(\\s+)|(<unicode>+|\\*)|\\#(<unicode>+)|\\.(<unicode>+)|\\[\\s*(<unicode1>+)(?:\\s*([*^$!~|]?=)(?:\\s*(?:([\"']?)(.*?)\\9)))?\\s*\\](?!\\])|(:+)(<unicode>+)(?:\\((?:(?:([\"'])([^\\13]*)\\13)|((?:\\([^)]+\\)|[^()]*)+))\\))?)"
              .replace(/<combinator>/, '[' + escapeRegExp(">+~`!@$%^&={}\\;</") + ']')
              .replace(/<unicode>/g, '(?:[\\w\\u00a1-\\uFFFF-]|\\\\[^\\s0-9a-f])')
              .replace(/<unicode1>/g, '(?:[:\\w\\u00a1-\\uFFFF-]|\\\\[^\\s0-9a-f])')
          );
  
          function parser(
              rawMatch,
  
              separator,
              combinator,
              combinatorChildren,
  
              tagName,
              id,
              className,
  
              attributeKey,
              attributeOperator,
              attributeQuote,
              attributeValue,
  
              pseudoMarker,
              pseudoClass,
              pseudoQuote,
              pseudoClassQuotedValue,
              pseudoClassValue
          ) {
              if (separator || separatorIndex === -1) {
                  parsed.expressions[++separatorIndex] = [];
                  combinatorIndex = -1;
                  if (separator) return '';
              }
  
              if (combinator || combinatorChildren || combinatorIndex === -1) {
                  combinator = combinator || ' ';
                  var currentSeparator = parsed.expressions[separatorIndex];
                  if (reversed && currentSeparator[combinatorIndex])
                      currentSeparator[combinatorIndex].reverseCombinator = reverseCombinator(combinator);
                  currentSeparator[++combinatorIndex] = {
                      combinator: combinator,
                      tag: '*'
                  };
              }
  
              var currentParsed = parsed.expressions[separatorIndex][combinatorIndex];
  
              if (tagName) {
                  currentParsed.tag = tagName.replace(reUnescape, '');
  
              } else if (id) {
                  currentParsed.id = id.replace(reUnescape, '');
  
              } else if (className) {
                  className = className.replace(reUnescape, '');
  
                  if (!currentParsed.classList) currentParsed.classList = [];
                  if (!currentParsed.classes) currentParsed.classes = [];
                  currentParsed.classList.push(className);
                  currentParsed.classes.push({
                      value: className,
                      regexp: new RegExp('(^|\\s)' + escapeRegExp(className) + '(\\s|$)')
                  });
  
              } else if (pseudoClass) {
                  pseudoClassValue = pseudoClassValue || pseudoClassQuotedValue;
                  pseudoClassValue = pseudoClassValue ? pseudoClassValue.replace(reUnescape, '') : null;
  
                  if (!currentParsed.pseudos) currentParsed.pseudos = [];
                  currentParsed.pseudos.push({
                      key: pseudoClass.replace(reUnescape, ''),
                      value: pseudoClassValue,
                      type: pseudoMarker.length == 1 ? 'class' : 'element'
                  });
  
              } else if (attributeKey) {
                  attributeKey = attributeKey.replace(reUnescape, '');
                  attributeValue = (attributeValue || '').replace(reUnescape, '');
  
                  var test, regexp;
  
                  switch (attributeOperator) {
                      case '^=':
                          regexp = new RegExp('^' + escapeRegExp(attributeValue));
                          break;
                      case '$=':
                          regexp = new RegExp(escapeRegExp(attributeValue) + '$');
                          break;
                      case '~=':
                          regexp = new RegExp('(^|\\s)' + escapeRegExp(attributeValue) + '(\\s|$)');
                          break;
                      case '|=':
                          regexp = new RegExp('^' + escapeRegExp(attributeValue) + '(-|$)');
                          break;
                      case '=':
                          test = function(value) {
                              return attributeValue == value;
                          };
                          break;
                      case '*=':
                          test = function(value) {
                              return value && value.indexOf(attributeValue) > -1;
                          };
                          break;
                      case '!=':
                          test = function(value) {
                              return attributeValue != value;
                          };
                          break;
                      default:
                          test = function(value) {
                              return !!value;
                          };
                  }
  
                  if (attributeValue == '' && (/^[*$^]=$/).test(attributeOperator)) test = function() {
                      return false;
                  };
  
                  if (!test) test = function(value) {
                      return value && regexp.test(value);
                  };
  
                  if (!currentParsed.attributes) currentParsed.attributes = [];
                  currentParsed.attributes.push({
                      key: attributeKey,
                      operator: attributeOperator,
                      value: attributeValue,
                      test: test
                  });
  
              }
  
              return '';
          };
  
          // Slick NS
  
          var Slick = (this.Slick || {});
  
          Slick.parse = function(expression) {
              return parse(expression);
          };
  
          Slick.escapeRegExp = escapeRegExp;
  
          if (!this.Slick) this.Slick = Slick;
  
      }).apply(local);
  
  
      var simpleClassSelectorRE = /^\.([\w-]*)$/,
          simpleIdSelectorRE = /^#([\w-]*)$/,
          rinputs = /^(?:input|select|textarea|button)$/i,
          rheader = /^h\d$/i,
          slice = Array.prototype.slice;
  
  
      local.parseSelector = local.Slick.parse;
  
  
      var pseudos = local.pseudos = {
          // custom pseudos
          "button": function(elem) {
              var name = elem.nodeName.toLowerCase();
              return name === "input" && elem.type === "button" || name === "button";
          },
  
          'checked': function(elm) {
              return !!elm.checked;
          },
  
          'contains': function(elm, idx, nodes, text) {
              if ($(this).text().indexOf(text) > -1) return this
          },
  
          'disabled': function(elm) {
              return !!elm.disabled;
          },
  
          'enabled': function(elm) {
              return !elm.disabled;
          },
  
          'eq': function(elm, idx, nodes, value) {
              return (idx == value);
          },
  
          'even': function(elm, idx, nodes, value) {
              return (idx % 2) === 0;
          },
  
          'focus': function(elm) {
              return document.activeElement === elm && (elm.href || elm.type || elm.tabindex);
          },
  
          'first': function(elm, idx) {
              return (idx === 0);
          },
  
          'gt': function(elm, idx, nodes, value) {
              return (idx > value);
          },
  
          'has': function(elm, idx, nodes, sel) {
              return find(elm, sel);
          },
  
          // Element/input types
          "header": function(elem) {
              return rheader.test(elem.nodeName);
          },
  
          'hidden': function(elm) {
              return !local.pseudos["visible"](elm);
          },
  
          "input": function(elem) {
              return rinputs.test(elem.nodeName);
          },
  
          'last': function(elm, idx, nodes) {
              return (idx === nodes.length - 1);
          },
  
          'lt': function(elm, idx, nodes, value) {
              return (idx < value);
          },
  
          'not': function(elm, idx, nodes, sel) {
              return !matches(elm, sel);
          },
  
          'odd': function(elm, idx, nodes, value) {
              return (idx % 2) === 1;
          },
  
          /*   
           * Get the parent of each element in the current set of matched elements.
           * @param {Object} elm
           */
          'parent': function(elm) {
              return !!elm.parentNode;
          },
  
          'selected': function(elm) {
              return !!elm.selected;
          },
  
          'text': function(elm) {
              return elm.type === "text";
          },
  
          'visible': function(elm) {
              return elm.offsetWidth && elm.offsetWidth
          }
      };
  
      ["first", "eq", "last"].forEach(function(item) {
          pseudos[item].isArrayFilter = true;
      });
  
  
  
      pseudos["nth"] = pseudos["eq"];
  
      function createInputPseudo(type) {
          return function(elem) {
              var name = elem.nodeName.toLowerCase();
              return name === "input" && elem.type === type;
          };
      }
  
      function createButtonPseudo(type) {
          return function(elem) {
              var name = elem.nodeName.toLowerCase();
              return (name === "input" || name === "button") && elem.type === type;
          };
      }
  
      // Add button/input type pseudos
      for (i in {
          radio: true,
          checkbox: true,
          file: true,
          password: true,
          image: true
      }) {
          pseudos[i] = createInputPseudo(i);
      }
      for (i in {
          submit: true,
          reset: true
      }) {
          pseudos[i] = createButtonPseudo(i);
      }
  
  
      local.divide = function(cond) {
          var nativeSelector = "",
              customPseudos = [],
              tag,
              id,
              classes,
              attributes,
              pseudos;
  
  
          if (id = cond.id) {
              nativeSelector += ("#" + id);
          }
          if (classes = cond.classes) {
              for (var i = classes.length; i--;) {
                  nativeSelector += ("." + classes[i].value);
              }
          }
          if (attributes = cond.attributes) {
              for (var i = 0; i < attributes.length; i++) {
                  if (attributes[i].operator) {
                      nativeSelector += ("[" + attributes[i].key + attributes[i].operator + JSON.stringify(attributes[i].value) + "]");
                  } else {
                      nativeSelector += ("[" + attributes[i].key + "]");
                  }
              }
          }
          if (pseudos = cond.pseudos) {
              for (i = pseudos.length; i--;) {
                  part = pseudos[i];
                  if (this.pseudos[part.key]) {
                      customPseudos.push(part);
                  } else {
                      if (part.value !== undefined) {
                          nativeSelector += (":" + part.key + "(" + JSON.stringify(part))
                      }
                  }
              }
          }
  
          if (tag = cond.tag) {
              if (tag !== "*") {
                  nativeSelector = tag.toUpperCase() + nativeSelector;
              }
          }
  
          if (!nativeSelector) {
              nativeSelector = "*";
          }
  
          return {
              nativeSelector: nativeSelector,
              customPseudos: customPseudos
          }
  
      };
  
      local.check = function(node, cond, idx, nodes, arrayFilte) {
          var tag,
              id,
              classes,
              attributes,
              pseudos,
  
              i, part, cls, pseudo;
  
          if (!arrayFilte) {
              if (tag = cond.tag) {
                  var nodeName = node.nodeName.toUpperCase();
                  if (tag == '*') {
                      if (nodeName < '@') return false; // Fix for comment nodes and closed nodes
                  } else {
                      if (nodeName != (tag || "").toUpperCase()) return false;
                  }
              }
  
              if (id = cond.id) {
                  if (node.getAttribute('id') != id) {
                      return false;
                  }
              }
  
  
              if (classes = cond.classes) {
                  for (i = classes.length; i--;) {
                      cls = node.getAttribute('class');
                      if (!(cls && classes[i].regexp.test(cls))) return false;
                  }
              }
  
              if (attributes = cond.attributes) {
                  for (i = attributes.length; i--;) {
                      part = attributes[i];
                      if (part.operator ? !part.test(node.getAttribute(part.key)) : !node.hasAttribute(part.key)) return false;
                  }
              }
  
          }
          if (pseudos = cond.pseudos) {
              for (i = pseudos.length; i--;) {
                  part = pseudos[i];
                  if (pseudo = this.pseudos[part.key]) {
                      if ((arrayFilte && pseudo.isArrayFilter) || (!arrayFilte && !pseudo.isArrayFilter)) {
                          if (!pseudo(node, idx, nodes, part.value)) {
                              return false;
                          }
                      }
                  } else {
                      if (!arrayFilte && !nativeMatchesSelector.call(node, part.key)) {
                          return false;
                      }
                  }
              }
          }
          return true;
      }
  
      local.match = function(node, selector) {
  
          var parsed;
  
          if (langx.isString(selector)) {
              parsed = local.Slick.parse(selector);
          } else {
              parsed = selector;
          }
  
          if (!parsed) {
              return true;
          }
  
          // simple (single) selectors
          var expressions = parsed.expressions,
              simpleExpCounter = 0,
              i,
              currentExpression;
          for (i = 0;
              (currentExpression = expressions[i]); i++) {
              if (currentExpression.length == 1) {
                  var exp = currentExpression[0];
                  if (this.check(node, exp)) {
                      return true;
                  }
                  simpleExpCounter++;
              }
          }
  
          if (simpleExpCounter == parsed.length) {
              return false;
          }
  
          var nodes = this.query(document, parsed),
              item;
          for (i = 0; item = nodes[i++];) {
              if (item === node) {
                  return true;
              }
          }
          return false;
      };
  
  
      local.filterSingle = function(nodes, exp) {
          var matchs = filter.call(nodes, function(node, idx) {
              return local.check(node, exp, idx, nodes, false);
          });
  
          matchs = filter.call(matchs, function(node, idx) {
              return local.check(node, exp, idx, matchs, true);
          });
          return matchs;
      };
  
      local.filter = function(nodes, selector) {
          var parsed;
  
          if (langx.isString(selector)) {
              parsed = local.Slick.parse(selector);
          } else {
              return local.filterSingle(nodes, selector);
          }
  
          // simple (single) selectors
          var expressions = parsed.expressions,
              i,
              currentExpression,
              ret = [];
          for (i = 0;
              (currentExpression = expressions[i]); i++) {
              if (currentExpression.length == 1) {
                  var exp = currentExpression[0];
  
                  var matchs = local.filterSingle(nodes, exp);
  
                  ret = langx.uniq(ret.concat(matchs));
              } else {
                  throw new Error("not supported selector:" + selector);
              }
          }
  
          return ret;
  
      };
  
      local.combine = function(elm, bit) {
          var op = bit.combinator,
              cond = bit,
              node1,
              nodes = [];
  
          switch (op) {
              case '>': // direct children
                  nodes = children(elm, cond);
                  break;
              case '+': // next sibling
                  node1 = nextSibling(elm, cond, true);
                  if (node1) {
                      nodes.push(node1);
                  }
                  break;
              case '^': // first child
                  node1 = firstChild(elm, cond, true);
                  if (node1) {
                      nodes.push(node1);
                  }
                  break;
              case '~': // next siblings
                  nodes = nextSiblings(elm, cond);
                  break;
              case '++': // next sibling and previous sibling
                  var prev = previousSibling(elm, cond, true),
                      next = nextSibling(elm, cond, true);
                  if (prev) {
                      nodes.push(prev);
                  }
                  if (next) {
                      nodes.push(next);
                  }
                  break;
              case '~~': // next siblings and previous siblings
                  nodes = siblings(elm, cond);
                  break;
              case '!': // all parent nodes up to document
                  nodes = ancestors(elm, cond);
                  break;
              case '!>': // direct parent (one level)
                  node1 = parent(elm, cond);
                  if (node1) {
                      nodes.push(node1);
                  }
                  break;
              case '!+': // previous sibling
                  nodes = previousSibling(elm, cond, true);
                  break;
              case '!^': // last child
                  node1 = lastChild(elm, cond, true);
                  if (node1) {
                      nodes.push(node1);
                  }
                  break;
              case '!~': // previous siblings
                  nodes = previousSiblings(elm, cond);
                  break;
              default:
                  var divided = this.divide(bit);
                  nodes = slice.call(elm.querySelectorAll(divided.nativeSelector));
                  if (divided.customPseudos) {
                      for (var i = divided.customPseudos.length - 1; i >= 0; i--) {
                          nodes = filter.call(nodes, function(item, idx) {
                              return local.check(item, {
                                  pseudos: [divided.customPseudos[i]]
                              }, idx, nodes, false)
                          });
  
                          nodes = filter.call(nodes, function(item, idx) {
                              return local.check(item, {
                                  pseudos: [divided.customPseudos[i]]
                              }, idx, nodes, true)
                          });
                      }
                  }
                  break;
  
          }
          return nodes;
      }
  
      local.query = function(node, selector, single) {
  
  
          var parsed = this.Slick.parse(selector);
  
          var
              founds = [],
              currentExpression, currentBit,
              expressions = parsed.expressions;
  
          for (var i = 0;
              (currentExpression = expressions[i]); i++) {
              var currentItems = [node],
                  found;
              for (var j = 0;
                  (currentBit = currentExpression[j]); j++) {
                  found = langx.map(currentItems, function(item, i) {
                      return local.combine(item, currentBit)
                  });
                  if (found) {
                      currentItems = found;
                  }
              }
              if (found) {
                  founds = founds.concat(found);
              }
          }
  
          return founds;
      }
  
      /*
       * Get the nearest ancestor of the specified element,optional matched by a selector.
       * @param {HTMLElement} node
       * @param {String Optional } selector
       * @param {Object} root
       */
      function ancestor(node, selector, root) {
          var rootIsSelector = root && langx.isString(root);
          while (node = node.parentNode) {
              if (matches(node, selector)) {
                  return node;
              }
              if (root) {
                  if (rootIsSelector) {
                      if (matches(node, root)) {
                          break;
                      }
                  } else if (node == root) {
                      break;
                  }
              }
          }
          return null;
      }
  
      /*
       * Get the ancestors of the specitied element , optionally filtered by a selector.
       * @param {HTMLElement} node
       * @param {String Optional } selector
       * @param {Object} root
       */
      function ancestors(node, selector, root) {
          var ret = [],
              rootIsSelector = root && langx.isString(root);
          while ((node = node.parentNode) && (node.nodeType !== 9)) {
              ret.push(node);
              if (root) {
                  if (rootIsSelector) {
                      if (matches(node, root)) {
                          break;
                      }
                  } else if (node == root) {
                      break;
                  }
              }
  
          }
  
          if (selector) {
              ret = local.filter(ret, selector);
          }
          return ret;
      }
  
      /*
       * Returns a element by its ID.
       * @param {string} id
       */
      function byId(id, doc) {
          doc = doc || noder.doc();
          return doc.getElementById(id);
      }
  
      /*
       * Get the children of the specified element , optionally filtered by a selector.
       * @param {string} node
       * @param {String optionlly} selector
       */
      function children(node, selector) {
          var childNodes = node.childNodes,
              ret = [];
          for (var i = 0; i < childNodes.length; i++) {
              var node = childNodes[i];
              if (node.nodeType == 1) {
                  ret.push(node);
              }
          }
          if (selector) {
              ret = local.filter(ret, selector);
          }
          return ret;
      }
  
      function closest(node, selector) {
          while (node && !(matches(node, selector))) {
              node = node.parentNode;
          }
  
          return node;
      }
  
      /*
       * Get the decendant of the specified element , optionally filtered by a selector.
       * @param {HTMLElement} elm
       * @param {String optionlly} selector
       */
      function descendants(elm, selector) {
          // Selector
          try {
              return slice.call(elm.querySelectorAll(selector));
          } catch (matchError) {
              //console.log(matchError);
          }
          return local.query(elm, selector);
      }
  
      /*
       * Get the nearest decendent of the specified element,optional matched by a selector.
       * @param {HTMLElement} elm
       * @param {String optionlly} selector
       */
      function descendant(elm, selector) {
          // Selector
          try {
              return elm.querySelector(selector);
          } catch (matchError) {
              //console.log(matchError);
          }
          var nodes = local.query(elm, selector);
          if (nodes.length > 0) {
              return nodes[0];
          } else {
              return null;
          }
      }
  
      /*
       * Get the descendants of each element in the current set of matched elements, filtered by a selector, jQuery object, or element.
       * @param {HTMLElement} elm
       * @param {String optionlly} selector
       */
      function find(elm, selector) {
          if (!selector) {
              selector = elm;
              elm = document.body;
          }
          if (matches(elm, selector)) {
              return elm;
          } else {
              return descendant(elm, selector);
          }
      }
  
      /*
       * Get the findAll of the specified element , optionally filtered by a selector.
       * @param {HTMLElement} elm
       * @param {String optionlly} selector
       */
      function findAll(elm, selector) {
          if (!selector) {
              selector = elm;
              elm = document.body;
          }
          return descendants(elm, selector);
      }
  
      /*
       * Get the first child of the specified element , optionally filtered by a selector.
       * @param {HTMLElement} elm
       * @param {String optionlly} selector
       * @param {String} first
       */
      function firstChild(elm, selector, first) {
          var childNodes = elm.childNodes,
              node = childNodes[0];
          while (node) {
              if (node.nodeType == 1) {
                  if (!selector || matches(node, selector)) {
                      return node;
                  }
                  if (first) {
                      break;
                  }
              }
              node = node.nextSibling;
          }
  
          return null;
      }
  
      /*
       * Get the last child of the specified element , optionally filtered by a selector.
       * @param {HTMLElement} elm
       * @param {String optionlly} selector
       * @param {String } last
       */
      function lastChild(elm, selector, last) {
          var childNodes = elm.childNodes,
              node = childNodes[childNodes.length - 1];
          while (node) {
              if (node.nodeType == 1) {
                  if (!selector || matches(node, selector)) {
                      return node;
                  }
                  if (last) {
                      break;
                  }
              }
              node = node.previousSibling;
          }
  
          return null;
      }
  
      /*
       * Check the specified element against a selector.
       * @param {HTMLElement} elm
       * @param {String optionlly} selector
       */
      function matches(elm, selector) {
          if (!selector || !elm || elm.nodeType !== 1) {
              return false
          }
  
          if (langx.isString(selector)) {
              try {
                  return nativeMatchesSelector.call(elm, selector.replace(/\[([^=]+)=\s*([^'"\]]+?)\s*\]/g, '[$1="$2"]'));
              } catch (matchError) {
                  //console.log(matchError);
              }
              return local.match(elm, selector);
          } else if (langx.isArrayLike(selector)) {
              return langx.inArray(elm, selector) > -1;
          } else if (langx.isPlainObject(selector)) {
              return local.check(elm, selector);
          } else {
              return elm === selector;
          }
  
      }
  
      /*
       * Get the nearest next sibing of the specitied element , optional matched by a selector.
       * @param {HTMLElement} elm
       * @param {String optionlly} selector
       * @param {Boolean Optional} adjacent
       */
      function nextSibling(elm, selector, adjacent) {
          var node = elm.nextSibling;
          while (node) {
              if (node.nodeType == 1) {
                  if (!selector || matches(node, selector)) {
                      return node;
                  }
                  if (adjacent) {
                      break;
                  }
              }
              node = node.nextSibling;
          }
          return null;
      }
  
      /*
       * Get the next siblings of the specified element , optional filtered by a selector.
       * @param {HTMLElement} elm
       * @param {String optionlly} selector
       */
      function nextSiblings(elm, selector) {
          var node = elm.nextSibling,
              ret = [];
          while (node) {
              if (node.nodeType == 1) {
                  if (!selector || matches(node, selector)) {
                      ret.push(node);
                  }
              }
              node = node.nextSibling;
          }
          return ret;
      }
  
      /*
       * Get the parent element of the specified element. if a selector is provided, it retrieves the parent element only if it matches that selector.
       * @param {HTMLElement} elm
       * @param {String optionlly} selector
       */
      function parent(elm, selector) {
          var node = elm.parentNode;
          if (node && (!selector || matches(node, selector))) {
              return node;
          }
  
          return null;
      }
  
      /*
       * Get hte nearest previous sibling of the specified element ,optional matched by a selector.
       * @param {HTMLElement} elm
       * @param {String optionlly} selector
       * @param {Boolean Optional } adjacent
       */
      function previousSibling(elm, selector, adjacent) {
          var node = elm.previousSibling;
          while (node) {
              if (node.nodeType == 1) {
                  if (!selector || matches(node, selector)) {
                      return node;
                  }
                  if (adjacent) {
                      break;
                  }
              }
              node = node.previousSibling;
          }
          return null;
      }
  
      /*
       * Get all preceding siblings of each element in the set of matched elements, optionally filtered by a selector.
       * @param {HTMLElement} elm
       * @param {String optionlly} selector
       */
      function previousSiblings(elm, selector) {
          var node = elm.previousSibling,
              ret = [];
          while (node) {
              if (node.nodeType == 1) {
                  if (!selector || matches(node, selector)) {
                      ret.push(node);
                  }
              }
              node = node.previousSibling;
          }
          return ret;
      }
  
      /*
       * Selects all sibling elements that follow after the “prev” element, have the same parent, and match the filtering “siblings” selector.
       * @param {HTMLElement} elm
       * @param {String optionlly} selector
       */
      function siblings(elm, selector) {
          var node = elm.parentNode.firstChild,
              ret = [];
          while (node) {
              if (node.nodeType == 1 && node !== elm) {
                  if (!selector || matches(node, selector)) {
                      ret.push(node);
                  }
              }
              node = node.nextSibling;
          }
          return ret;
      }
  
      var finder = function() {
          return finder;
      };
  
      langx.mixin(finder, {
  
          ancestor: ancestor,
  
          ancestors: ancestors,
  
          byId: byId,
  
          children: children,
  
          closest: closest,
  
          descendant: descendant,
  
          descendants: descendants,
  
          find: find,
  
          findAll: findAll,
  
          firstChild: firstChild,
  
          lastChild: lastChild,
  
          matches: matches,
  
          nextSibling: nextSibling,
  
          nextSiblings: nextSiblings,
  
          parent: parent,
  
          previousSibling: previousSibling,
  
          previousSiblings: previousSiblings,
  
          pseudos: local.pseudos,
  
          siblings: siblings
      });
  
      return skylark.finder = finder;
  });
  define('skylark-utils/datax',[
      "./skylark",
      "./langx",
      "./finder"
  ], function(skylark, langx, finder) {
      var map = Array.prototype.map,
          filter = Array.prototype.filter,
          camelCase = langx.camelCase,
          deserializeValue = langx.deserializeValue,
  
          capitalRE = /([A-Z])/g,
          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'
          };
      /*
       * Set property values
       * @param {Object} elm  
       * @param {String} name
       * @param {String} value
       */
  
      function setAttribute(elm, name, value) {
          if (value == null) {
              elm.removeAttribute(name);
          } else {
              elm.setAttribute(name, value);
          }
      }
  
      function aria(elm, name, value) {
          return this.attr(elm, "aria-" + name, value);
      }
  
      /*
       * Set property values
       * @param {Object} elm  
       * @param {String} name
       * @param {String} value
       */
  
      function attr(elm, name, value) {
          if (value === undefined) {
              if (typeof name === "object") {
                  for (var attrName in name) {
                      attr(elm, attrName, name[attrName]);
                  }
                  return this;
              } else {
                  if (elm.hasAttribute && elm.hasAttribute(name)) {
                      return elm.getAttribute(name);
                  }
              }
          } else {
              elm.setAttribute(name, value);
              return this;
          }
      }
  
  
      /*
       *  Read all "data-*" attributes from a node
       * @param {Object} elm  
       */
  
      function _attributeData(elm) {
          var store = {}
          langx.each(elm.attributes || [], function(i, attr) {
              if (attr.name.indexOf('data-') == 0) {
                  store[camelCase(attr.name.replace('data-', ''))] = deserializeValue(attr.value);
              }
          })
          return store;
      }
  
      function _store(elm, confirm) {
          var store = elm["_$_store"];
          if (!store && confirm) {
              store = elm["_$_store"] = _attributeData(elm);
          }
          return store;
      }
  
      function _getData(elm, name) {
          if (name === undefined) {
              return _store(elm, true);
          } else {
              var store = _store(elm);
              if (store) {
                  if (name in store) {
                      return store[name];
                  }
                  var camelName = camelCase(name);
                  if (camelName in store) {
                      return store[camelName];
                  }
              }
              var attrName = 'data-' + name.replace(capitalRE, "-$1").toLowerCase()
              return attr(elm, attrName);
          }
  
      }
  
      function _setData(elm, name, value) {
          var store = _store(elm, true);
          store[camelCase(name)] = value;
      }
  
  
      /*
       * xxx
       * @param {Object} elm  
       * @param {String} name
       * @param {String} value
       */
      function data(elm, name, value) {
  
          if (value === undefined) {
              if (typeof name === "object") {
                  for (var dataAttrName in name) {
                      _setData(elm, dataAttrName, name[dataAttrName]);
                  }
                  return this;
              } else {
                  return _getData(elm, name);
              }
          } else {
              _setData(elm, name, value);
              return this;
          }
      } 
      /*
       * Remove from the element all items that have not yet been run. 
       * @param {Object} elm  
       */
  
      function cleanData(elm) {
          if (elm["_$_store"]) {
              delete elm["_$_store"];
          }
      }
  
      /*
       * Remove a previously-stored piece of data. 
       * @param {Object} elm  
       * @param {Array} names
       */
      function removeData(elm, names) {
          if (langx.isString(names)) {
              names = names.split(/\s+/);
          }
          var store = _store(elm, true);
          names.forEach(function(name) {
              delete store[name];
          });
          return this;
      }
  
      /*
       * xxx 
       * @param {Object} elm  
       * @param {Array} names
       */
      function pluck(nodes, property) {
          return map.call(nodes, function(elm) {
              return elm[property];
          });
      }
  
      /*
       * Get or set the value of an property for the specified element.
       * @param {Object} elm  
       * @param {String} name
       * @param {String} value
       */
      function prop(elm, name, value) {
          name = propMap[name] || name;
          if (value === undefined) {
              return elm[name];
          } else {
              elm[name] = value;
              return this;
          }
      }
  
      /*
       * remove Attributes  
       * @param {Object} elm  
       * @param {String} name
       */
      function removeAttr(elm, name) {
          name.split(' ').forEach(function(attr) {
              setAttribute(elm, attr);
          });
          return this;
      }
  
  
      /*
       * Remove the value of a property for the first element in the set of matched elements or set one or more properties for every matched element.
       * @param {Object} elm  
       * @param {String} name
       */
      function removeProp(elm, name) {
          name.split(' ').forEach(function(prop) {
              delete elm[prop];
          });
          return this;
      }
  
      /*   
       * Get the combined text contents of each element in the set of matched elements, including their descendants, or set the text contents of the matched elements.  
       * @param {Object} elm  
       * @param {String} txt
       */
      function text(elm, txt) {
          if (txt === undefined) {
              return elm.textContent;
          } else {
              elm.textContent = txt == null ? '' : '' + txt;
              return this;
          }
      }
  
      /*   
       * Get the current value of the first element in the set of matched elements or set the value of every matched element.
       * @param {Object} elm  
       * @param {String} value
       */
      function val(elm, value) {
          if (value === undefined) {
              if (elm.multiple) {
                  // select multiple values
                  var selectedOptions = filter.call(finder.find(elm, "option"), (function(option) {
                      return option.selected;
                  }));
                  return pluck(selectedOptions, "value");
              } else {
                  return elm.value;
              }
          } else {
              elm.value = value;
              return this;
          }
      }
  
      function datax() {
          return datax;
      }
  
      langx.mixin(datax, {
          aria: aria,
  
          attr: attr,
  
          cleanData: cleanData,
  
          data: data,
  
          pluck: pluck,
  
          prop: prop,
  
          removeAttr: removeAttr,
  
          removeData: removeData,
  
          removeProp: removeProp,
  
          text: text,
  
          val: val
      });
  
      return skylark.datax = datax;
  });
  define('skylarkjs/datax',[
      "skylark-utils/datax"
  ], function(datax) {
      return datax;
  });
  
  define('skylark-utils/geom',[
      "./skylark",
      "./langx",
      "./noder",
      "./styler"
  ], function(skylark, langx, noder, styler) {
      var rootNodeRE = /^(?:body|html)$/i,
          px = langx.toPixel,
          offsetParent = noder.offsetParent,
          cachedScrollbarWidth;
  
      function scrollbarWidth() {
          if (cachedScrollbarWidth !== undefined) {
              return cachedScrollbarWidth;
          }
          var w1, w2,
              div = noder.createFragment("<div style=" +
                  "'display:block;position:absolute;width:200px;height:200px;overflow:hidden;'>" +
                  "<div style='height:300px;width:auto;'></div></div>")[0],
              innerDiv = div.childNodes[0];
  
          noder.append(document.body, div);
  
          w1 = innerDiv.offsetWidth;
  
          styler.css(div, "overflow", "scroll");
  
          w2 = innerDiv.offsetWidth;
  
          if (w1 === w2) {
              w2 = div[0].clientWidth;
          }
  
          noder.remove(div);
  
          return (cachedScrollbarWidth = w1 - w2);
      }
      /*
       * Get the widths of each border of the specified element.
       * @param {HTMLElement} elm
       */
      function borderExtents(elm) {
          var s = getComputedStyle(elm);
          return {
              left: px(s.borderLeftWidth, elm),
              top: px(s.borderTopWidth, elm),
              right: px(s.borderRightWidth, elm),
              bottom: px(s.borderBottomWidth, elm)
          }
      }
  
      //viewport coordinate
      /*
       * Get or set the viewport position of the specified element border box.
       * @param {HTMLElement} elm
       * @param {PlainObject} coords
       */
      function boundingPosition(elm, coords) {
          if (coords === undefined) {
              return rootNodeRE.test(elm.nodeName) ? { top: 0, left: 0 } : elm.getBoundingClientRect();
          } else {
              var // Get *real* offsetParent
                  parent = offsetParent(elm),
                  // Get correct offsets
                  parentOffset = boundingPosition(parent),
                  mex = marginExtents(elm),
                  pbex = borderExtents(parent);
  
              relativePosition(elm, {
                  top: coords.top - parentOffset.top - mex.top - pbex.top,
                  left: coords.left - parentOffset.left - mex.left - pbex.left
              });
              return this;
          }
      }
  
      /*
       * Get or set the viewport rect of the specified element border box.
       * @param {HTMLElement} elm
       * @param {PlainObject} coords
       */
      function boundingRect(elm, coords) {
          if (coords === undefined) {
              return elm.getBoundingClientRect()
          } else {
              boundingPosition(elm, coords);
              size(elm, coords);
              return this;
          }
      }
  
      /*
       * Get or set the height of the specified element client box.
       * @param {HTMLElement} elm
       * @param {Number} value
       */
      function clientHeight(elm, value) {
          if (value == undefined) {
              return clientSize(elm).height;
          } else {
              return clientSize(elm, {
                  height: value
              });
          }
      }
  
      /*
       * Get or set the size of the specified element client box.
       * @param {HTMLElement} elm
       * @param {PlainObject} dimension
       */
      function clientSize(elm, dimension) {
          if (dimension == undefined) {
              return {
                  width: elm.clientWidth,
                  height: elm.clientHeight
              }
          } else {
              var isBorderBox = (styler.css(elm, "box-sizing") === "border-box"),
                  props = {
                      width: dimension.width,
                      height: dimension.height
                  };
              if (!isBorderBox) {
                  var pex = paddingExtents(elm);
  
                  if (props.width !== undefined) {
                      props.width = props.width - pex.left - pex.right;
                  }
  
                  if (props.height !== undefined) {
                      props.height = props.height - pex.top - pex.bottom;
                  }
              } else {
                  var bex = borderExtents(elm);
  
                  if (props.width !== undefined) {
                      props.width = props.width + bex.left + bex.right;
                  }
  
                  if (props.height !== undefined) {
                      props.height = props.height + bex.top + bex.bottom;
                  }
  
              }
              styler.css(elm, props);
              return this;
          }
          return {
              width: elm.clientWidth,
              height: elm.clientHeight
          };
      }
  
      /*
       * Get or set the width of the specified element client box.
       * @param {HTMLElement} elm
       * @param {PlainObject} dimension
       */
      function clientWidth(elm, value) {
          if (value == undefined) {
              return clientSize(elm).width;
          } else {
              clientSize(elm, {
                  width: value
              });
              return this;
          }
      }
  
      /*
       * Get the rect of the specified element content box.
       * @param {HTMLElement} elm
       */
      function contentRect(elm) {
          var cs = clientSize(elm),
              pex = paddingExtents(elm);
  
  
          //// On Opera, offsetLeft includes the parent's border
          //if(has("opera")){
          //    pe.l += be.l;
          //    pe.t += be.t;
          //}
          return {
              left: pex.left,
              top: pex.top,
              width: cs.width - pex.left - pex.right,
              height: cs.height - pex.top - pex.bottom
          };
      }
  
      /*
       * Get the document size.
       * @param {HTMLDocument} doc
       */
      function getDocumentSize(doc) {
          var documentElement = doc.documentElement,
              body = doc.body,
              max = Math.max,
              scrollWidth = max(documentElement.scrollWidth, body.scrollWidth),
              clientWidth = max(documentElement.clientWidth, body.clientWidth),
              offsetWidth = max(documentElement.offsetWidth, body.offsetWidth),
              scrollHeight = max(documentElement.scrollHeight, body.scrollHeight),
              clientHeight = max(documentElement.clientHeight, body.clientHeight),
              offsetHeight = max(documentElement.offsetHeight, body.offsetHeight);
  
          return {
              width: scrollWidth < offsetWidth ? clientWidth : scrollWidth,
              height: scrollHeight < offsetHeight ? clientHeight : scrollHeight
          };
      }
  
      /*
       * Get the document size.
       * @param {HTMLElement} elm
       * @param {Number} value
       */
      function height(elm, value) {
          if (value == undefined) {
              return size(elm).height;
          } else {
              size(elm, {
                  height: value
              });
              return this;
          }
      }
  
      /*
       * Get the widths of each margin of the specified element.
       * @param {HTMLElement} elm
       */
      function marginExtents(elm) {
          var s = getComputedStyle(elm);
          return {
              left: px(s.marginLeft),
              top: px(s.marginTop),
              right: px(s.marginRight),
              bottom: px(s.marginBottom),
          }
      }
  
  
      function marginRect(elm) {
          var obj = this.relativeRect(elm),
              me = this.marginExtents(elm);
  
          return {
              left: obj.left,
              top: obj.top,
              width: obj.width + me.left + me.right,
              height: obj.height + me.top + me.bottom
          };
      }
  
  
      function marginSize(elm) {
          var obj = this.size(elm),
              me = this.marginExtents(elm);
  
          return {
              width: obj.width + me.left + me.right,
              height: obj.height + me.top + me.bottom
          };
      }
  
      /*
       * Get the widths of each padding of the specified element.
       * @param {HTMLElement} elm
       */
      function paddingExtents(elm) {
          var s = getComputedStyle(elm);
          return {
              left: px(s.paddingLeft),
              top: px(s.paddingTop),
              right: px(s.paddingRight),
              bottom: px(s.paddingBottom),
          }
      }
  
      /*
       * Get or set the document position of the specified element border box.
       * @param {HTMLElement} elm
       * @param {PlainObject} coords
       */
      //coordinate to the document
      function pagePosition(elm, coords) {
          if (coords === undefined) {
              var obj = elm.getBoundingClientRect()
              return {
                  left: obj.left + window.pageXOffset,
                  top: obj.top + window.pageYOffset
              }
          } else {
              var // Get *real* offsetParent
                  parent = offsetParent(elm),
                  // Get correct offsets
                  parentOffset = pagePosition(parent),
                  mex = marginExtents(elm),
                  pbex = borderExtents(parent);
  
              relativePosition(elm, {
                  top: coords.top - parentOffset.top - mex.top - pbex.top,
                  left: coords.left - parentOffset.left - mex.left - pbex.left
              });
              return this;
          }
      }
  
      /*
       * Get or set the document rect of the specified element border box.
       * @param {HTMLElement} elm
       * @param {PlainObject} coords
       */
      function pageRect(elm, coords) {
          if (coords === undefined) {
              var obj = elm.getBoundingClientRect()
              return {
                  left: obj.left + window.pageXOffset,
                  top: obj.top + window.pageYOffset,
                  width: Math.round(obj.width),
                  height: Math.round(obj.height)
              }
          } else {
              pagePosition(elm, coords);
              size(elm, coords);
              return this;
          }
      }
  
      /*
       * Get or set the position of the specified element border box , relative to parent element.
       * @param {HTMLElement} elm
       * @param {PlainObject} coords
       */
      // coordinate relative to it's parent
      function relativePosition(elm, coords) {
          if (coords == undefined) {
              var // Get *real* offsetParent
                  parent = offsetParent(elm),
                  // Get correct offsets
                  offset = boundingPosition(elm),
                  parentOffset = boundingPosition(parent),
                  mex = marginExtents(elm),
                  pbex = borderExtents(parent);
  
              // Subtract parent offsets and element margins
              return {
                  top: offset.top - parentOffset.top - pbex.top, // - mex.top,
                  left: offset.left - parentOffset.left - pbex.left, // - mex.left
              }
          } else {
              var props = {
                  top: coords.top,
                  left: coords.left
              }
  
              if (styler.css(elm, "position") == "static") {
                  props['position'] = "relative";
              }
              styler.css(elm, props);
              return this;
          }
      }
  
      /*
       * Get or set the rect of the specified element border box , relatived to parent element.
       * @param {HTMLElement} elm
       * @param {PlainObject} coords
       */
      function relativeRect(elm, coords) {
          if (coords === undefined) {
              var // Get *real* offsetParent
                  parent = offsetParent(elm),
                  // Get correct offsets
                  offset = boundingRect(elm),
                  parentOffset = boundingPosition(parent),
                  mex = marginExtents(elm),
                  pbex = borderExtents(parent);
  
              // Subtract parent offsets and element margins
              return {
                  top: offset.top - parentOffset.top - pbex.top, // - mex.top,
                  left: offset.left - parentOffset.left - pbex.left, // - mex.left,
                  width: offset.width,
                  height: offset.height
              }
          } else {
              relativePosition(elm, coords);
              size(elm, coords);
              return this;
          }
      }
      /*
       * Scroll the specified element into view.
       * @param {HTMLElement} elm
       * @param {} align
       */
      function scrollIntoView(elm, align) {
          function getOffset(elm, rootElm) {
              var x, y, parent = elm;
  
              x = y = 0;
              while (parent && parent != rootElm && parent.nodeType) {
                  x += parent.offsetLeft || 0;
                  y += parent.offsetTop || 0;
                  parent = parent.offsetParent;
              }
  
              return { x: x, y: y };
          }
  
          var parentElm = elm.parentNode;
          var x, y, width, height, parentWidth, parentHeight;
          var pos = getOffset(elm, parentElm);
  
          x = pos.x;
          y = pos.y;
          width = elm.offsetWidth;
          height = elm.offsetHeight;
          parentWidth = parentElm.clientWidth;
          parentHeight = parentElm.clientHeight;
  
          if (align == "end") {
              x -= parentWidth - width;
              y -= parentHeight - height;
          } else if (align == "center") {
              x -= (parentWidth / 2) - (width / 2);
              y -= (parentHeight / 2) - (height / 2);
          }
  
          parentElm.scrollLeft = x;
          parentElm.scrollTop = y;
  
          return this;
      }
      /*
       * Get or set the current horizontal position of the scroll bar for the specified element.
       * @param {HTMLElement} elm
       * @param {Number} value
       */
      function scrollLeft(elm, value) {
          var hasScrollLeft = "scrollLeft" in elm;
          if (value === undefined) {
              return hasScrollLeft ? elm.scrollLeft : elm.pageXOffset
          } else {
              if (hasScrollLeft) {
                  elm.scrollLeft = value;
              } else {
                  elm.scrollTo(value, elm.scrollY);
              }
              return this;
          }
      }
      /*
       * Get or the current vertical position of the scroll bar for the specified element.
       * @param {HTMLElement} elm
       * @param {Number} value
       */
      function scrollTop(elm, value) {
          var hasScrollTop = "scrollTop" in elm;
  
          if (value === undefined) {
              return hasScrollTop ? elm.scrollTop : elm.pageYOffset
          } else {
              if (hasScrollTop) {
                  elm.scrollTop = value;
              } else {
                  elm.scrollTo(elm.scrollX, value);
              }
              return this;
          }
      }
      /*
       * Get or set the size of the specified element border box.
       * @param {HTMLElement} elm
       * @param {PlainObject}dimension
       */
      function size(elm, dimension) {
          if (dimension == undefined) {
              if (langx.isWindow(elm)) {
                  return {
                      width: elm.innerWidth,
                      height: elm.innerHeight
                  }
  
              } else if (langx.isDocument(elm)) {
                  return getDocumentSize(document);
              } else {
                  return {
                      width: elm.offsetWidth,
                      height: elm.offsetHeight
                  }
              }
          } else {
              var isBorderBox = (styler.css(elm, "box-sizing") === "border-box"),
                  props = {
                      width: dimension.width,
                      height: dimension.height
                  };
              if (!isBorderBox) {
                  var pex = paddingExtents(elm),
                      bex = borderExtents(elm);
  
                  if (props.width !== undefined && props.width !== "" && props.width !== null) {
                      props.width = props.width - pex.left - pex.right - bex.left - bex.right;
                  }
  
                  if (props.height !== undefined && props.height !== "" && props.height !== null) {
                      props.height = props.height - pex.top - pex.bottom - bex.top - bex.bottom;
                  }
              }
              styler.css(elm, props);
              return this;
          }
      }
      /*
       * Get or set the size of the specified element border box.
       * @param {HTMLElement} elm
       * @param {Number} value
       */
      function width(elm, value) {
          if (value == undefined) {
              return size(elm).width;
          } else {
              size(elm, {
                  width: value
              });
              return this;
          }
      }
      
  // in development start
      function _place(/*DomNode*/ node, choices, layoutNode, aroundNodeCoords){
          // summary:
          //      Given a list of spots to put node, put it at the first spot where it fits,
          //      of if it doesn't fit anywhere then the place with the least overflow
          // choices: Array
          //      Array of elements like: {corner: 'TL', pos: {x: 10, y: 20} }
          //      Above example says to put the top-left corner of the node at (10,20)
          // layoutNode: Function(node, aroundNodeCorner, nodeCorner, size)
          //      for things like tooltip, they are displayed differently (and have different dimensions)
          //      based on their orientation relative to the parent.   This adjusts the popup based on orientation.
          //      It also passes in the available size for the popup, which is useful for tooltips to
          //      tell them that their width is limited to a certain amount.   layoutNode() may return a value expressing
          //      how much the popup had to be modified to fit into the available space.   This is used to determine
          //      what the best placement is.
          // aroundNodeCoords: Object
          //      Size of aroundNode, ex: {w: 200, h: 50}
  
          // get {x: 10, y: 10, w: 100, h:100} type obj representing position of
          // viewport over document
  
          var doc = noder.ownerDoc(node),
              win = noder.ownerWindow(doc),
              view = geom.size(win);
  
          view.left = 0;
          view.top = 0;
  
          if(!node.parentNode || String(node.parentNode.tagName).toLowerCase() != "body"){
              doc.body.appendChild(node);
          }
  
          var best = null;
  
          some.apply(choices, function(choice){
              var corner = choice.corner;
              var pos = choice.pos;
              var overflow = 0;
  
              // calculate amount of space available given specified position of node
              var spaceAvailable = {
                  w: {
                      'L': view.left + view.width - pos.x,
                      'R': pos.x - view.left,
                      'M': view.width
                  }[corner.charAt(1)],
  
                  h: {
                      'T': view.top + view.height - pos.y,
                      'B': pos.y - view.top,
                      'M': view.height
                  }[corner.charAt(0)]
              };
  
              if(layoutNode){
                  var res = layoutNode(node, choice.aroundCorner, corner, spaceAvailable, aroundNodeCoords);
                  overflow = typeof res == "undefined" ? 0 : res;
              }
  
              var bb = geom.size(node);
  
              // coordinates and size of node with specified corner placed at pos,
              // and clipped by viewport
              var
                  startXpos = {
                      'L': pos.x,
                      'R': pos.x - bb.width,
                      'M': Math.max(view.left, Math.min(view.left + view.width, pos.x + (bb.width >> 1)) - bb.width) // M orientation is more flexible
                  }[corner.charAt(1)],
  
                  startYpos = {
                      'T': pos.y,
                      'B': pos.y - bb.height,
                      'M': Math.max(view.top, Math.min(view.top + view.height, pos.y + (bb.height >> 1)) - bb.height)
                  }[corner.charAt(0)],
  
                  startX = Math.max(view.left, startXpos),
                  startY = Math.max(view.top, startYpos),
                  endX = Math.min(view.left + view.width, startXpos + bb.width),
                  endY = Math.min(view.top + view.height, startYpos + bb.height),
                  width = endX - startX,
                  height = endY - startY;
  
              overflow += (bb.width - width) + (bb.height - height);
  
              if(best == null || overflow < best.overflow){
                  best = {
                      corner: corner,
                      aroundCorner: choice.aroundCorner,
                      left: startX,
                      top: startY,
                      width: width,
                      height: height,
                      overflow: overflow,
                      spaceAvailable: spaceAvailable
                  };
              }
  
              return !overflow;
          });
  
          // In case the best position is not the last one we checked, need to call
          // layoutNode() again.
          if(best.overflow && layoutNode){
              layoutNode(node, best.aroundCorner, best.corner, best.spaceAvailable, aroundNodeCoords);
          }
  
  
          geom.boundingPosition(node,best);
  
          return best;
      }
  
      function at(node, pos, corners, padding, layoutNode){
          var choices = map.apply(corners, function(corner){
              var c = {
                  corner: corner,
                  aroundCorner: reverse[corner],  // so TooltipDialog.orient() gets aroundCorner argument set
                  pos: {x: pos.x,y: pos.y}
              };
              if(padding){
                  c.pos.x += corner.charAt(1) == 'L' ? padding.x : -padding.x;
                  c.pos.y += corner.charAt(0) == 'T' ? padding.y : -padding.y;
              }
              return c;
          });
  
          return _place(node, choices, layoutNode);
      }
  
      function around(
          /*DomNode*/     node,
          /*DomNode|__Rectangle*/ anchor,
          /*String[]*/    positions,
          /*Boolean*/     leftToRight,
          /*Function?*/   layoutNode){
  
          // summary:
          //      Position node adjacent or kitty-corner to anchor
          //      such that it's fully visible in viewport.
          // description:
          //      Place node such that corner of node touches a corner of
          //      aroundNode, and that node is fully visible.
          // anchor:
          //      Either a DOMNode or a rectangle (object with x, y, width, height).
          // positions:
          //      Ordered list of positions to try matching up.
          //
          //      - before: places drop down to the left of the anchor node/widget, or to the right in the case
          //          of RTL scripts like Hebrew and Arabic; aligns either the top of the drop down
          //          with the top of the anchor, or the bottom of the drop down with bottom of the anchor.
          //      - after: places drop down to the right of the anchor node/widget, or to the left in the case
          //          of RTL scripts like Hebrew and Arabic; aligns either the top of the drop down
          //          with the top of the anchor, or the bottom of the drop down with bottom of the anchor.
          //      - before-centered: centers drop down to the left of the anchor node/widget, or to the right
          //          in the case of RTL scripts like Hebrew and Arabic
          //      - after-centered: centers drop down to the right of the anchor node/widget, or to the left
          //          in the case of RTL scripts like Hebrew and Arabic
          //      - above-centered: drop down is centered above anchor node
          //      - above: drop down goes above anchor node, left sides aligned
          //      - above-alt: drop down goes above anchor node, right sides aligned
          //      - below-centered: drop down is centered above anchor node
          //      - below: drop down goes below anchor node
          //      - below-alt: drop down goes below anchor node, right sides aligned
          // layoutNode: Function(node, aroundNodeCorner, nodeCorner)
          //      For things like tooltip, they are displayed differently (and have different dimensions)
          //      based on their orientation relative to the parent.   This adjusts the popup based on orientation.
          // leftToRight:
          //      True if widget is LTR, false if widget is RTL.   Affects the behavior of "above" and "below"
          //      positions slightly.
          // example:
          //  |   placeAroundNode(node, aroundNode, {'BL':'TL', 'TR':'BR'});
          //      This will try to position node such that node's top-left corner is at the same position
          //      as the bottom left corner of the aroundNode (ie, put node below
          //      aroundNode, with left edges aligned).   If that fails it will try to put
          //      the bottom-right corner of node where the top right corner of aroundNode is
          //      (ie, put node above aroundNode, with right edges aligned)
          //
  
          // If around is a DOMNode (or DOMNode id), convert to coordinates.
          var aroundNodePos;
          if(typeof anchor == "string" || "offsetWidth" in anchor || "ownerSVGElement" in anchor){
              aroundNodePos = domGeometry.position(anchor, true);
  
              // For above and below dropdowns, subtract width of border so that popup and aroundNode borders
              // overlap, preventing a double-border effect.  Unfortunately, difficult to measure the border
              // width of either anchor or popup because in both cases the border may be on an inner node.
              if(/^(above|below)/.test(positions[0])){
                  var anchorBorder = domGeometry.getBorderExtents(anchor),
                      anchorChildBorder = anchor.firstChild ? domGeometry.getBorderExtents(anchor.firstChild) : {t:0,l:0,b:0,r:0},
                      nodeBorder =  domGeometry.getBorderExtents(node),
                      nodeChildBorder = node.firstChild ? domGeometry.getBorderExtents(node.firstChild) : {t:0,l:0,b:0,r:0};
                  aroundNodePos.y += Math.min(anchorBorder.t + anchorChildBorder.t, nodeBorder.t + nodeChildBorder.t);
                  aroundNodePos.h -=  Math.min(anchorBorder.t + anchorChildBorder.t, nodeBorder.t+ nodeChildBorder.t) +
                      Math.min(anchorBorder.b + anchorChildBorder.b, nodeBorder.b + nodeChildBorder.b);
              }
          }else{
              aroundNodePos = anchor;
          }
  
          // Compute position and size of visible part of anchor (it may be partially hidden by ancestor nodes w/scrollbars)
          if(anchor.parentNode){
              // ignore nodes between position:relative and position:absolute
              var sawPosAbsolute = domStyle.getComputedStyle(anchor).position == "absolute";
              var parent = anchor.parentNode;
              while(parent && parent.nodeType == 1 && parent.nodeName != "BODY"){  //ignoring the body will help performance
                  var parentPos = domGeometry.position(parent, true),
                      pcs = domStyle.getComputedStyle(parent);
                  if(/relative|absolute/.test(pcs.position)){
                      sawPosAbsolute = false;
                  }
                  if(!sawPosAbsolute && /hidden|auto|scroll/.test(pcs.overflow)){
                      var bottomYCoord = Math.min(aroundNodePos.y + aroundNodePos.h, parentPos.y + parentPos.h);
                      var rightXCoord = Math.min(aroundNodePos.x + aroundNodePos.w, parentPos.x + parentPos.w);
                      aroundNodePos.x = Math.max(aroundNodePos.x, parentPos.x);
                      aroundNodePos.y = Math.max(aroundNodePos.y, parentPos.y);
                      aroundNodePos.h = bottomYCoord - aroundNodePos.y;
                      aroundNodePos.w = rightXCoord - aroundNodePos.x;
                  }
                  if(pcs.position == "absolute"){
                      sawPosAbsolute = true;
                  }
                  parent = parent.parentNode;
              }
          }           
  
          var x = aroundNodePos.x,
              y = aroundNodePos.y,
              width = "w" in aroundNodePos ? aroundNodePos.w : (aroundNodePos.w = aroundNodePos.width),
              height = "h" in aroundNodePos ? aroundNodePos.h : (kernel.deprecated("place.around: dijit/place.__Rectangle: { x:"+x+", y:"+y+", height:"+aroundNodePos.height+", width:"+width+" } has been deprecated.  Please use { x:"+x+", y:"+y+", h:"+aroundNodePos.height+", w:"+width+" }", "", "2.0"), aroundNodePos.h = aroundNodePos.height);
  
          // Convert positions arguments into choices argument for _place()
          var choices = [];
          function push(aroundCorner, corner){
              choices.push({
                  aroundCorner: aroundCorner,
                  corner: corner,
                  pos: {
                      x: {
                          'L': x,
                          'R': x + width,
                          'M': x + (width >> 1)
                      }[aroundCorner.charAt(1)],
                      y: {
                          'T': y,
                          'B': y + height,
                          'M': y + (height >> 1)
                      }[aroundCorner.charAt(0)]
                  }
              })
          }
          array.forEach(positions, function(pos){
              var ltr =  leftToRight;
              switch(pos){
                  case "above-centered":
                      push("TM", "BM");
                      break;
                  case "below-centered":
                      push("BM", "TM");
                      break;
                  case "after-centered":
                      ltr = !ltr;
                      // fall through
                  case "before-centered":
                      push(ltr ? "ML" : "MR", ltr ? "MR" : "ML");
                      break;
                  case "after":
                      ltr = !ltr;
                      // fall through
                  case "before":
                      push(ltr ? "TL" : "TR", ltr ? "TR" : "TL");
                      push(ltr ? "BL" : "BR", ltr ? "BR" : "BL");
                      break;
                  case "below-alt":
                      ltr = !ltr;
                      // fall through
                  case "below":
                      // first try to align left borders, next try to align right borders (or reverse for RTL mode)
                      push(ltr ? "BL" : "BR", ltr ? "TL" : "TR");
                      push(ltr ? "BR" : "BL", ltr ? "TR" : "TL");
                      break;
                  case "above-alt":
                      ltr = !ltr;
                      // fall through
                  case "above":
                      // first try to align left borders, next try to align right borders (or reverse for RTL mode)
                      push(ltr ? "TL" : "TR", ltr ? "BL" : "BR");
                      push(ltr ? "TR" : "TL", ltr ? "BR" : "BL");
                      break;
                  default:
                      // To assist dijit/_base/place, accept arguments of type {aroundCorner: "BL", corner: "TL"}.
                      // Not meant to be used directly.  Remove for 2.0.
                      push(pos.aroundCorner, pos.corner);
              }
          });
  
          var position = _place(node, choices, layoutNode, {w: width, h: height});
          position.aroundNodePos = aroundNodePos;
  
          return position;
      }
  // in development end
  
      function geom() {
          return geom;
      }
  
      langx.mixin(geom, {
          borderExtents: borderExtents,
          //viewport coordinate
          boundingPosition: boundingPosition,
  
          boundingRect: boundingRect,
  
          clientHeight: clientHeight,
  
          clientSize: clientSize,
  
          clientWidth: clientWidth,
  
          contentRect: contentRect,
  
          getDocumentSize: getDocumentSize,
  
          height: height,
  
          marginExtents: marginExtents,
  
          marginRect: marginRect,
  
          marginSize: marginSize,
  
          offsetParent: offsetParent,
  
          paddingExtents: paddingExtents,
  
          //coordinate to the document
          pagePosition: pagePosition,
  
          pageRect: pageRect,
  
          // coordinate relative to it's parent
          relativePosition: relativePosition,
  
          relativeRect: relativeRect,
  
          scrollbarWidth: scrollbarWidth,
  
          scrollIntoView: scrollIntoView,
  
          scrollLeft: scrollLeft,
  
          scrollTop: scrollTop,
  
          size: size,
  
          width: width
      });
  
      return skylark.geom = geom;
  });
  define('skylark-utils/eventer',[
      "./skylark",
      "./langx",
      "./browser",
      "./finder",
      "./noder",
      "./datax"
  ], function(skylark, langx, browser, finder, noder, datax) {
      var mixin = langx.mixin,
          each = langx.each,
          slice = Array.prototype.slice,
          uid = langx.uid,
          ignoreProperties = /^([A-Z]|returnValue$|layer[XY]$)/,
          eventMethods = {
              preventDefault: "isDefaultPrevented",
              stopImmediatePropagation: "isImmediatePropagationStopped",
              stopPropagation: "isPropagationStopped"
          },
          readyRE = /complete|loaded|interactive/;
  
      function compatible(event, source) {
          if (source || !event.isDefaultPrevented) {
              if (!source) {
                  source = event;
              }
  
              langx.each(eventMethods, function(name, predicate) {
                  var sourceMethod = source[name];
                  event[name] = function() {
                      this[predicate] = langx.returnTrue;
                      return sourceMethod && sourceMethod.apply(source, arguments);
                  }
                  event[predicate] = langx.returnFalse;
              });
          }
          return event;
      }
  
      function parse(event) {
          var segs = ("" + event).split(".");
          return {
              type: segs[0],
              ns: segs.slice(1).sort().join(" ")
          };
      }
  
      //create a custom dom event
      var createEvent = (function() {
          var EventCtors = [
                  window["CustomEvent"], // 0 default
                  window["CompositionEvent"], // 1
                  window["DragEvent"], // 2
                  window["Event"], // 3
                  window["FocusEvent"], // 4
                  window["KeyboardEvent"], // 5
                  window["MessageEvent"], // 6
                  window["MouseEvent"], // 7
                  window["MouseScrollEvent"], // 8
                  window["MouseWheelEvent"], // 9
                  window["MutationEvent"], // 10
                  window["ProgressEvent"], // 11
                  window["TextEvent"], // 12
                  window["TouchEvent"], // 13
                  window["UIEvent"], // 14
                  window["WheelEvent"], // 15
                  window["ClipboardEvent"] // 16
              ],
              NativeEvents = {
                  "compositionstart": 1, // CompositionEvent
                  "compositionend": 1, // CompositionEvent
                  "compositionupdate": 1, // CompositionEvent
  
                  "beforecopy": 16, // ClipboardEvent
                  "beforecut": 16, // ClipboardEvent
                  "beforepaste": 16, // ClipboardEvent
                  "copy": 16, // ClipboardEvent
                  "cut": 16, // ClipboardEvent
                  "paste": 16, // ClipboardEvent
  
                  "drag": 2, // DragEvent
                  "dragend": 2, // DragEvent
                  "dragenter": 2, // DragEvent
                  "dragexit": 2, // DragEvent
                  "dragleave": 2, // DragEvent
                  "dragover": 2, // DragEvent
                  "dragstart": 2, // DragEvent
                  "drop": 2, // DragEvent
  
                  "abort": 3, // Event
                  "change": 3, // Event
                  "error": 3, // Event
                  "selectionchange": 3, // Event
                  "submit": 3, // Event
                  "reset": 3, // Event
  
                  "focus": 4, // FocusEvent
                  "blur": 4, // FocusEvent
                  "focusin": 4, // FocusEvent
                  "focusout": 4, // FocusEvent
  
                  "keydown": 5, // KeyboardEvent
                  "keypress": 5, // KeyboardEvent
                  "keyup": 5, // KeyboardEvent
  
                  "message": 6, // MessageEvent
  
                  "click": 7, // MouseEvent
                  "contextmenu": 7, // MouseEvent
                  "dblclick": 7, // MouseEvent
                  "mousedown": 7, // MouseEvent
                  "mouseup": 7, // MouseEvent
                  "mousemove": 7, // MouseEvent
                  "mouseover": 7, // MouseEvent
                  "mouseout": 7, // MouseEvent
                  "mouseenter": 7, // MouseEvent
                  "mouseleave": 7, // MouseEvent
  
  
                  "textInput": 12, // TextEvent
  
                  "touchstart": 13, // TouchEvent
                  "touchmove": 13, // TouchEvent
                  "touchend": 13, // TouchEvent
  
                  "load": 14, // UIEvent
                  "resize": 14, // UIEvent
                  "select": 14, // UIEvent
                  "scroll": 14, // UIEvent
                  "unload": 14, // UIEvent,
  
                  "wheel": 15 // WheelEvent
              };
  
          function getEventCtor(type) {
              var idx = NativeEvents[type];
              if (!idx) {
                  idx = 0;
              }
              return EventCtors[idx];
          }
  
          return function(type, props) {
              //create a custom dom event
  
              if (langx.isString(type)) {
                  props = props || {};
              } else {
                  props = type || {};
                  type = props.type || "";
              }
              var parsed = parse(type);
              type = parsed.type;
  
              props = langx.mixin({
                  bubbles: true,
                  cancelable: true
              }, props);
  
              if (parsed.ns) {
                  props.namespace = parsed.ns;
              }
  
              var ctor = getEventCtor(type),
                  e = new ctor(type, props);
  
              langx.safeMixin(e, props);
  
              return compatible(e);
          };
      })();
  
      function createProxy(src, props) {
          var key,
              proxy = {
                  originalEvent: src
              };
          for (key in src) {
              if (key !== "keyIdentifier" && !ignoreProperties.test(key) && src[key] !== undefined) {
                  proxy[key] = src[key];
              }
          }
          if (props) {
              langx.mixin(proxy, props);
          }
          return compatible(proxy, src);
      }
  
      var
          specialEvents = {},
          focusinSupported = "onfocusin" in window,
          focus = { focus: "focusin", blur: "focusout" },
          hover = { mouseenter: "mouseover", mouseleave: "mouseout" },
          realEvent = function(type) {
              return hover[type] || (focusinSupported && focus[type]) || type;
          },
          handlers = {},
          EventBindings = langx.klass({
              init: function(target, event) {
                  this._target = target;
                  this._event = event;
                  this._bindings = [];
              },
  
              add: function(fn, options) {
                  var bindings = this._bindings,
                      binding = {
                          fn: fn,
                          options: langx.mixin({}, options)
                      };
  
                  bindings.push(binding);
  
                  var self = this;
                  if (!self._listener) {
                      self._listener = function(domEvt) {
                          var elm = this,
                              e = createProxy(domEvt),
                              args = domEvt._args,
                              bindings = self._bindings,
                              ns = e.namespace;
  
                          if (langx.isDefined(args)) {
                              args = [e].concat(args);
                          } else {
                              args = [e];
                          }
  
                          langx.each(bindings, function(idx, binding) {
                              var match = elm;
                              if (e.isImmediatePropagationStopped && e.isImmediatePropagationStopped()) {
                                  return false;
                              }
                              var fn = binding.fn,
                                  options = binding.options || {},
                                  selector = options.selector,
                                  one = options.one,
                                  data = options.data;
  
                              if (ns && ns != options.ns && options.ns.indexOf(ns) === -1) {
                                  return;
                              }
                              if (selector) {
                                  match = finder.closest(e.target, selector);
                                  if (match && match !== elm) {
                                      langx.mixin(e, {
                                          currentTarget: match,
                                          liveFired: elm
                                      });
                                  } else {
                                      return;
                                  }
                              }
  
                              var originalEvent = self._event;
                              if (originalEvent in hover) {
                                  var related = e.relatedTarget;
                                  if (related && (related === match || noder.contains(match, related))) {
                                      return;
                                  }
                              }
  
                              if (langx.isDefined(data)) {
                                  e.data = data;
                              }
  
                              if (one) {
                                  self.remove(fn, options);
                              }
  
                              var result = fn.apply(match, args);
  
                              if (result === false) {
                                  e.preventDefault();
                                  e.stopPropagation();
                              }
                          });;
                      };
  
                      var event = self._event;
                      /*
                                          if (event in hover) {
                                              var l = self._listener;
                                              self._listener = function(e) {
                                                  var related = e.relatedTarget;
                                                  if (!related || (related !== this && !noder.contains(this, related))) {
                                                      return l.apply(this, arguments);
                                                  }
                                              }
                                          }
                      */
  
                      if (self._target.addEventListener) {
                          self._target.addEventListener(realEvent(event), self._listener, false);
                      } else {
                          console.warn("invalid eventer object", self._target);
                      }
                  }
  
              },
              remove: function(fn, options) {
                  options = langx.mixin({}, options);
  
                  function matcherFor(ns) {
                      return new RegExp("(?:^| )" + ns.replace(" ", " .* ?") + "(?: |$)");
                  }
                  var matcher;
                  if (options.ns) {
                      matcher = matcherFor(options.ns);
                  }
  
                  this._bindings = this._bindings.filter(function(binding) {
                      var removing = (!fn || fn === binding.fn) &&
                          (!matcher || matcher.test(binding.options.ns)) &&
                          (!options.selector || options.selector == binding.options.selector);
  
                      return !removing;
                  });
                  if (this._bindings.length == 0) {
                      if (this._target.removeEventListener) {
                          this._target.removeEventListener(realEvent(this._event), this._listener, false);
                      }
                      this._listener = null;
                  }
              }
          }),
          EventsHandler = langx.klass({
              init: function(elm) {
                  this._target = elm;
                  this._handler = {};
              },
  
              // add a event listener
              // selector Optional
              register: function(event, callback, options) {
                  // Seperate the event from the namespace
                  var parsed = parse(event),
                      event = parsed.type,
                      specialEvent = specialEvents[event],
                      bindingEvent = specialEvent && (specialEvent.bindType || specialEvent.bindEventName);
  
                  var events = this._handler;
  
                  // Check if there is already a handler for this event
                  if (events[event] === undefined) {
                      events[event] = new EventBindings(this._target, bindingEvent || event);
                  }
  
                  // Register the new callback function
                  events[event].add(callback, langx.mixin({
                      ns: parsed.ns
                  }, options)); // options:{selector:xxx}
              },
  
              // remove a event listener
              unregister: function(event, fn, options) {
                  // Check for parameter validtiy
                  var events = this._handler,
                      parsed = parse(event);
                  event = parsed.type;
  
                  if (event) {
                      var listener = events[event];
  
                      if (listener) {
                          listener.remove(fn, langx.mixin({
                              ns: parsed.ns
                          }, options));
                      }
                  } else {
                      //remove all events
                      for (event in events) {
                          var listener = events[event];
                          listener.remove(fn, langx.mixin({
                              ns: parsed.ns
                          }, options));
                      }
                  }
              }
          }),
  
          findHandler = function(elm) {
              var id = uid(elm),
                  handler = handlers[id];
              if (!handler) {
                  handler = handlers[id] = new EventsHandler(elm);
              }
              return handler;
          };
  
      /*   
       * Remove an event handler for one or more events from the specified element.
       * @param {HTMLElement} elm  
       * @param {String} events
       * @param {String　Optional } selector
       * @param {Function} callback
       */
      function off(elm, events, selector, callback) {
          var $this = this
          if (langx.isPlainObject(events)) {
              langx.each(events, function(type, fn) {
                  off(elm, type, selector, fn);
              })
              return $this;
          }
  
          if (!langx.isString(selector) && !langx.isFunction(callback) && callback !== false) {
              callback = selector;
              selector = undefined;
          }
  
          if (callback === false) {
              callback = langx.returnFalse;
          }
  
          if (typeof events == "string") {
              if (events.indexOf(",") > -1) {
                  events = events.split(",");
              } else {
                  events = events.split(/\s/);
              }
          }
  
          var handler = findHandler(elm);
  
          if (events) events.forEach(function(event) {
  
              handler.unregister(event, callback, {
                  selector: selector,
              });
          });
          return this;
      }
  
      /*   
       * Attach an event handler function for one or more events to the selected elements.
       * @param {HTMLElement} elm  
       * @param {String} events
       * @param {String　Optional} selector
       * @param {Anything Optional} data
       * @param {Function} callback
       * @param {Boolean　Optional} one
       */
      function on(elm, events, selector, data, callback, one) {
  
          var autoRemove, delegator;
          if (langx.isPlainObject(events)) {
              langx.each(events, function(type, fn) {
                  on(elm, type, selector, data, fn, one);
              });
              return this;
          }
  
          if (!langx.isString(selector) && !langx.isFunction(callback)) {
              callback = data;
              data = selector;
              selector = undefined;
          }
  
          if (langx.isFunction(data)) {
              callback = data;
              data = undefined;
          }
  
          if (callback === false) {
              callback = langx.returnFalse;
          }
  
          if (typeof events == "string") {
              if (events.indexOf(",") > -1) {
                  events = events.split(",");
              } else {
                  events = events.split(/\s/);
              }
          }
  
          var handler = findHandler(elm);
  
          events.forEach(function(event) {
              if (event == "ready") {
                  return ready(callback);
              }
              handler.register(event, callback, {
                  data: data,
                  selector: selector,
                  one: !!one
              });
          });
          return this;
      }
  
      /*   
       * Attach a handler to an event for the elements. The handler is executed at most once per 
       * @param {HTMLElement} elm  
       * @param {String} event
       * @param {String　Optional} selector
       * @param {Anything Optional} data
       * @param {Function} callback
       */
      function one(elm, events, selector, data, callback) {
          on(elm, events, selector, data, callback, 1);
  
          return this;
      }
  
      /*   
       * Prevents propagation and clobbers the default action of the passed event. The same as calling event.preventDefault() and event.stopPropagation(). 
       * @param {String} event
       */
      function stop(event) {
          if (window.document.all) {
              event.keyCode = 0;
          }
          if (event.preventDefault) {
              event.preventDefault();
              event.stopPropagation();
          }
          return this;
      }
      /*   
       * Execute all handlers and behaviors attached to the matched elements for the given event  
       * @param {String} evented
       * @param {String} type
       * @param {Array or PlainObject } args
       */
      function trigger(evented, type, args) {
          var e;
          if (type instanceof Event) {
              e = type;
          } else {
              e = createEvent(type, args);
          }
          e._args = args;
  
          var fn = (evented.dispatchEvent || evented.trigger);
          if (fn) {
              fn.call(evented, e);
          } else {
              console.warn("The evented parameter is not a eventable object");
          }
  
          return this;
      }
      /*   
       * Specify a function to execute when the DOM is fully loaded.  
       * @param {Function} callback
       */
      function ready(callback) {
          // need to check if document.body exists for IE as that browser reports
          // document ready when it hasn't yet created the body elm
          if (readyRE.test(document.readyState) && document.body) {
              langx.defer(callback);
          } else {
              document.addEventListener('DOMContentLoaded', callback, false);
          }
  
          return this;
      }
  
      var keyCodeLookup = {
          "backspace": 8,
          "comma": 188,
          "delete": 46,
          "down": 40,
          "end": 35,
          "enter": 13,
          "escape": 27,
          "home": 36,
          "left": 37,
          "page_down": 34,
          "page_up": 33,
          "period": 190,
          "right": 39,
          "space": 32,
          "tab": 9,
          "up": 38
      };
      //example:
      //shortcuts(elm).add("CTRL+ALT+SHIFT+X",function(){console.log("test!")});
      function shortcuts(elm) {
  
          var registry = datax.data(elm, "shortcuts");
          if (!registry) {
              registry = {};
              datax.data(elm, "shortcuts", registry);
              var run = function(shortcut, event) {
                  var n = event.metaKey || event.ctrlKey;
                  if (shortcut.ctrl == n && shortcut.alt == event.altKey && shortcut.shift == event.shiftKey) {
                      if (event.keyCode == shortcut.keyCode || event.charCode && event.charCode == shortcut.charCode) {
                          event.preventDefault();
                          if ("keydown" == event.type) {
                              shortcut.fn(event);
                          }
                          return true;
                      }
                  }
              };
              on(elm, "keyup keypress keydown", function(event) {
                  if (!(/INPUT|TEXTAREA/.test(event.target.nodeName))) {
                      for (var key in registry) {
                          run(registry[key], event);
                      }
                  }
              });
  
          }
  
          return {
              add: function(pattern, fn) {
                  var shortcutKeys;
                  if (pattern.indexOf(",") > -1) {
                      shortcutKeys = pattern.toLowerCase().split(",");
                  } else {
                      shortcutKeys = pattern.toLowerCase().split(" ");
                  }
                  shortcutKeys.forEach(function(shortcutKey) {
                      var setting = {
                          fn: fn,
                          alt: false,
                          ctrl: false,
                          shift: false
                      };
                      shortcutKey.split("+").forEach(function(key) {
                          switch (key) {
                              case "alt":
                              case "ctrl":
                              case "shift":
                                  setting[key] = true;
                                  break;
                              default:
                                  setting.charCode = key.charCodeAt(0);
                                  setting.keyCode = keyCodeLookup[key] || key.toUpperCase().charCodeAt(0);
                          }
                      });
                      var regKey = (setting.ctrl ? "ctrl" : "") + "," + (setting.alt ? "alt" : "") + "," + (setting.shift ? "shift" : "") + "," + setting.keyCode;
                      registry[regKey] = setting;
                  })
              }
  
          };
  
      }
  
      function eventer() {
          return eventer;
      }
  
      langx.mixin(eventer, {
          create: createEvent,
  
          keys: keyCodeLookup,
  
          off: off,
  
          on: on,
  
          one: one,
  
          proxy: createProxy,
  
          ready: ready,
  
          shortcuts: shortcuts,
  
          special: specialEvents,
  
          stop: stop,
  
          trigger: trigger
  
      });
  
      return skylark.eventer = eventer;
  });
  define('skylark-utils/dnd',[
      "./skylark",
      "./langx",
      "./noder",
      "./datax",
      "./finder",
      "./geom",
      "./eventer",
      "./styler"
  ], function(skylark, langx, noder, datax, finder, geom, eventer, styler) {
      var on = eventer.on,
          off = eventer.off,
          attr = datax.attr,
          removeAttr = datax.removeAttr,
          offset = geom.pagePosition,
          addClass = styler.addClass,
          height = geom.height;
  
  
      var DndManager = langx.Evented.inherit({
          klassName: "DndManager",
  
          init: function() {
  
          },
  
          prepare: function(draggable) {
              var e = eventer.create("preparing", {
                  dragSource: draggable.dragSource,
                  dragHandle: draggable.dragHandle
              });
              draggable.trigger(e);
              draggable.dragSource = e.dragSource;
          },
  
          start: function(draggable, event) {
  
              var p = geom.pagePosition(draggable.dragSource);
              this.draggingOffsetX = parseInt(event.pageX - p.left);
              this.draggingOffsetY = parseInt(event.pageY - p.top)
  
              var e = eventer.create("started", {
                  elm: draggable.elm,
                  dragSource: draggable.dragSource,
                  dragHandle: draggable.dragHandle,
                  ghost: null,
  
                  transfer: {}
              });
  
              draggable.trigger(e);
  
  
              this.dragging = draggable;
  
              if (draggable.draggingClass) {
                  styler.addClass(draggable.dragSource, draggable.draggingClass);
              }
  
              this.draggingGhost = e.ghost;
              if (!this.draggingGhost) {
                  this.draggingGhost = draggable.elm;
              }
  
              this.draggingTransfer = e.transfer;
              if (this.draggingTransfer) {
  
                  langx.each(this.draggingTransfer, function(key, value) {
                      event.dataTransfer.setData(key, value);
                  });
              }
  
              event.dataTransfer.setDragImage(this.draggingGhost, this.draggingOffsetX, this.draggingOffsetY);
  
              event.dataTransfer.effectAllowed = "copyMove";
  
              var e1 = eventer.create("dndStarted", {
                  elm: e.elm,
                  dragSource: e.dragSource,
                  dragHandle: e.dragHandle,
                  ghost: e.ghost,
                  transfer: e.transfer
              });
  
              this.trigger(e1);
          },
  
          over: function() {
  
          },
  
          end: function(dropped) {
              var dragging = this.dragging;
              if (dragging) {
                  if (dragging.draggingClass) {
                      styler.removeClass(dragging.dragSource, dragging.draggingClass);
                  }
              }
  
              var e = eventer.create("dndEnded", {});
              this.trigger(e);
  
  
              this.dragging = null;
              this.draggingTransfer = null;
              this.draggingGhost = null;
              this.draggingOffsetX = null;
              this.draggingOffsetY = null;
          }
      });
  
      var manager = new DndManager(),
          draggingHeight,
          placeholders = [];
  
  
  
      var Draggable = langx.Evented.inherit({
          klassName: "Draggable",
  
          init: function(elm, params) {
              var self = this;
  
              self.elm = elm;
              self.draggingClass = params.draggingClass || "dragging",
                  self.params = langx.clone(params);
  
              ["preparing", "started", "ended", "moving"].forEach(function(eventName) {
                  if (langx.isFunction(params[eventName])) {
                      self.on(eventName, params[eventName]);
                  }
              });
  
  
              eventer.on(elm, {
                  "mousedown": function(e) {
                      var params = self.params;
                      if (params.handle) {
                          self.dragHandle = finder.closest(e.target, params.handle);
                          if (!self.dragHandle) {
                              return;
                          }
                      }
                      if (params.source) {
                          self.dragSource = finder.closest(e.target, params.source);
                      } else {
                          self.dragSource = self.elm;
                      }
                      manager.prepare(self);
                      if (self.dragSource) {
                          datax.attr(self.dragSource, "draggable", 'true');
                      }
                  },
  
                  "mouseup": function(e) {
                      if (self.dragSource) {
                          //datax.attr(self.dragSource, "draggable", 'false');
                          self.dragSource = null;
                          self.dragHandle = null;
                      }
                  },
  
                  "dragstart": function(e) {
                      datax.attr(self.dragSource, "draggable", 'false');
                      manager.start(self, e);
                  },
  
                  "dragend": function(e) {
                      eventer.stop(e);
  
                      if (!manager.dragging) {
                          return;
                      }
  
                      manager.end(false);
                  }
              });
  
          }
  
      });
  
  
      var Droppable = langx.Evented.inherit({
          klassName: "Droppable",
  
          init: function(elm, params) {
              var self = this,
                  draggingClass = params.draggingClass || "dragging",
                  hoverClass,
                  activeClass,
                  acceptable = true;
  
              self.elm = elm;
              self._params = params;
  
              ["started", "entered", "leaved", "dropped", "overing"].forEach(function(eventName) {
                  if (langx.isFunction(params[eventName])) {
                      self.on(eventName, params[eventName]);
                  }
              });
  
              eventer.on(elm, {
                  "dragover": function(e) {
                      e.stopPropagation()
  
                      if (!acceptable) {
                          return
                      }
  
                      var e2 = eventer.create("overing", {
                          overElm: e.target,
                          transfer: manager.draggingTransfer,
                          acceptable: true
                      });
                      self.trigger(e2);
  
                      if (e2.acceptable) {
                          e.preventDefault() // allow drop
  
                          e.dataTransfer.dropEffect = "copyMove";
                      }
  
                  },
  
                  "dragenter": function(e) {
                      var params = self._params,
                          elm = self.elm;
  
                      var e2 = eventer.create("entered", {
                          transfer: manager.draggingTransfer
                      });
  
                      self.trigger(e2);
  
                      e.stopPropagation()
  
                      if (hoverClass && acceptable) {
                          styler.addClass(elm, hoverClass)
                      }
                  },
  
                  "dragleave": function(e) {
                      var params = self._params,
                          elm = self.elm;
                      if (!acceptable) return false
  
                      var e2 = eventer.create("leaved", {
                          transfer: manager.draggingTransfer
                      });
  
                      self.trigger(e2);
  
                      e.stopPropagation()
  
                      if (hoverClass && acceptable) {
                          styler.removeClass(elm, hoverClass);
                      }
                  },
  
                  "drop": function(e) {
                      var params = self._params,
                          elm = self.elm;
  
                      eventer.stop(e); // stops the browser from redirecting.
  
                      if (!manager.dragging) return
  
                      // manager.dragging.elm.removeClass('dragging');
  
                      if (hoverClass && acceptable) {
                          styler.addClass(elm, hoverClass)
                      }
  
                      var e2 = eventer.create("dropped", {
                          transfer: manager.draggingTransfer
                      });
  
                      self.trigger(e2);
  
                      manager.end(true)
                  }
              });
  
              manager.on("dndStarted", function(e) {
                  var e2 = eventer.create("started", {
                      transfer: manager.draggingTransfer,
                      acceptable: false
                  });
  
                  self.trigger(e2);
  
                  acceptable = e2.acceptable;
                  hoverClass = e2.hoverClass;
                  activeClass = e2.activeClass;
  
                  if (activeClass && acceptable) {
                      styler.addClass(elm, activeClass);
                  }
  
              }).on("dndEnded", function(e) {
                  var e2 = eventer.create("ended", {
                      transfer: manager.draggingTransfer,
                      acceptable: false
                  });
  
                  self.trigger(e2);
  
                  if (hoverClass && acceptable) {
                      styler.removeClass(elm, hoverClass);
                  }
                  if (activeClass && acceptable) {
                      styler.removeClass(elm, activeClass);
                  }
  
                  acceptable = false;
                  activeClass = null;
                  hoverClass = null;
              });
  
          }
      });
  
  
      /*   
       * Make the specified element be in a moveable state.
       * @param {HTMLElement} elm  
       * @param { } params
       */
      function draggable(elm, params) {
          return new Draggable(elm, params);
      }
  
      /*   
       * Make the specified element be in a droppable state.
       * @param {HTMLElement} elm  
       * @param { } params
       */
      function droppable(elm, params) {
          return new Droppable(elm, params);
      }
  
  
      function dnd() {
          return dnd;
      }
  
      langx.mixin(dnd, {
          //params ： {
          //  target : Element or string or function
          //  handle : Element
          //  copy : boolean
          //  placeHolder : "div"
          //  hoverClass : "hover"
          //  start : function
          //  enter : function
          //  over : function
          //  leave : function
          //  drop : function
          //  end : function
          //
          //
          //}
          draggable: draggable,
  
          //params ： {
          //  accept : string or function
          //  placeHolder
          //
          //
          //
          //}
          droppable: droppable,
  
          manager: manager
  
  
      });
  
      return skylark.dnd = dnd;
  });
  define('skylarkjs/dnd',[
      "skylark-utils/dnd"
  ], function(dnd) {
      return dnd;
  });
  
  define('skylarkjs/eventer',[
      "skylark-utils/eventer"
  ], function(eventer) {
      return eventer;
  });
  
  define('skylark-utils/filer',[
      "./skylark",
      "./langx",
      "./datax",
      "./eventer",
      "./styler"
  ], function(skylark, langx, datax, eventer, styler) {
      var concat = Array.prototype.concat,
          on = eventer.on,
          attr = eventer.attr,
          Deferred = langx.Deferred,
  
          fileInput,
          fileInputForm,
          fileSelected,
          maxFileSize = 1 / 0;
  
  
      var webentry = (function() {
          function one(entry, path) {
              var d = new Deferred(),
                  onError = function(e) {
                      d.reject(e);
                  };
  
              path = path || '';
              if (entry.isFile) {
                  entry.file(function(file) {
                      file.relativePath = path;
                      d.resolve(file);
                  }, onError);
              } else if (entry.isDirectory) {
                  var dirReader = entry.createReader();
                  dirReader.readEntries(function(entries) {
                      all(
                          entries,
                          path + entry.name + '/'
                      ).then(function(files) {
                          d.resolve(files);
                      }).catch(onError);
                  }, onError);
              } else {
                  // Return an empy list for file system items
                  // other than files or directories:
                  d.resolve([]);
              }
              return d.promise;
          }
  
          function all(entries, path) {
              return Deferred.all(
                  langx.map(entries, function(entry) {
                      return one(entry, path);
                  })
              ).then(function() {
                  return concat.apply([], arguments);
              });
          }
  
          return {
              one: one,
              all: all
          };
      })();
  
      function dataURLtoBlob(dataurl) {
          var arr = dataurl.split(','),
              mime = arr[0].match(/:(.*?);/)[1],
              bstr = atob(arr[1]),
              n = bstr.length,
              u8arr = new Uint8Array(n);
          while (n--) {
              u8arr[n] = bstr.charCodeAt(n);
          }
          return new Blob([u8arr], { type: mime });
      }
      /*
       * Make the specified element to could accept HTML5 file drag and drop.
       * @param {HTMLElement} elm
       * @param {PlainObject} params
       */
      function dropzone(elm, params) {
          params = params || {};
          var hoverClass = params.hoverClass || "dropzone",
              droppedCallback = params.dropped;
  
          var enterdCount = 0;
          on(elm, "dragenter", function(e) {
              if (e.dataTransfer && e.dataTransfer.types.indexOf("Files") > -1) {
                  eventer.stop(e);
                  enterdCount++;
                  styler.addClass(elm, hoverClass)
              }
          });
  
          on(elm, "dragover", function(e) {
              if (e.dataTransfer && e.dataTransfer.types.indexOf("Files") > -1) {
                  eventer.stop(e);
              }
          });
  
          on(elm, "dragleave", function(e) {
              if (e.dataTransfer && e.dataTransfer.types.indexOf("Files") > -1) {
                  enterdCount--
                  if (enterdCount == 0) {
                      styler.removeClass(elm, hoverClass);
                  }
              }
          });
  
          on(elm, "drop", function(e) {
              if (e.dataTransfer && e.dataTransfer.types.indexOf("Files") > -1) {
                  styler.removeClass(elm, hoverClass)
                  eventer.stop(e);
                  if (droppedCallback) {
                      var items = e.dataTransfer.items;
                      if (items && items.length && (items[0].webkitGetAsEntry ||
                              items[0].getAsEntry)) {
                          webentry.all(
                              langx.map(items, function(item) {
                                  if (item.webkitGetAsEntry) {
                                      return item.webkitGetAsEntry();
                                  }
                                  return item.getAsEntry();
                              })
                          ).then(droppedCallback);
                      } else {
                          droppedCallback(e.dataTransfer.files);
                      }
                  }
              }
          });
  
          return this;
      }
  
      function pastezone(elm, params) {
          params = params || {};
          var hoverClass = params.hoverClass || "pastezone",
              pastedCallback = params.pasted;
  
          on(elm, "paste", function(e) {
              var items = e.originalEvent && e.originalEvent.clipboardData &&
                  e.originalEvent.clipboardData.items,
                  files = [];
              if (items && items.length) {
                  langx.each(items, function(index, item) {
                      var file = item.getAsFile && item.getAsFile();
                      if (file) {
                          files.push(file);
                      }
                  });
              }
              if (pastedCallback && files.length) {
                  pastedCallback(files);
              }
          });
  
          return this;
      }
      /*
       * Make the specified element to pop-up the file selection dialog box when clicked , and read the contents the files selected from client file system by user.
       * @param {HTMLElement} elm
       * @param {PlainObject} params
       */
      function picker(elm, params) {
          on(elm, "click", function(e) {
              e.preventDefault();
              select(params);
          });
          return this;
      }
  
      function select(params) {
          params = params || {};
          var directory = params.directory || false,
              multiple = params.multiple || false,
              fileSelected = params.picked;
          if (!fileInput) {
              var input = fileInput = document.createElement("input");
  
              function selectFiles(pickedFiles) {
                  for (var i = pickedFiles.length; i--;) {
                      if (pickedFiles[i].size > maxFileSize) {
                          pickedFiles.splice(i, 1);
                      }
                  }
                  fileSelected(pickedFiles);
              }
  
              input.type = "file";
              input.style.position = "fixed",
                  input.style.left = 0,
                  input.style.top = 0,
                  input.style.opacity = .001,
                  document.body.appendChild(input);
  
              input.onchange = function(e) {
                  var entries = e.target.webkitEntries || e.target.entries;
  
                  if (entries && entries.length) {
                      webentry.all(entries).then(function(files) {
                          selectFiles(files);
                      });
                  } else {
                      selectFiles(Array.prototype.slice.call(e.target.files));
                  }
                  // reset to "", so selecting the same file next time still trigger the change handler
                  input.value = "";
              };
          }
          fileInput.multiple = multiple;
          fileInput.webkitdirectory = directory;
          fileInput.click();
      }
  
      function upload(params) {
          var xoptions = langx.mixin({
              contentRange: null, //
  
              // The parameter name for the file form data (the request argument name).
              // If undefined or empty, the name property of the file input field is
              // used, or "files[]" if the file input name property is also empty,
              // can be a string or an array of strings:
              paramName: undefined,
              // By default, each file of a selection is uploaded using an individual
              // request for XHR type uploads. Set to false to upload file
              // selections in one request each:
              singleFileUploads: true,
              // To limit the number of files uploaded with one XHR request,
              // set the following option to an integer greater than 0:
              limitMultiFileUploads: undefined,
              // The following option limits the number of files uploaded with one
              // XHR request to keep the request size under or equal to the defined
              // limit in bytes:
              limitMultiFileUploadSize: undefined,
              // Multipart file uploads add a number of bytes to each uploaded file,
              // therefore the following option adds an overhead for each file used
              // in the limitMultiFileUploadSize configuration:
              limitMultiFileUploadSizeOverhead: 512,
              // Set the following option to true to issue all file upload requests
              // in a sequential order:
              sequentialUploads: false,
              // To limit the number of concurrent uploads,
              // set the following option to an integer greater than 0:
              limitConcurrentUploads: undefined,
              // By default, XHR file uploads are sent as multipart/form-data.
              // The iframe transport is always using multipart/form-data.
              // Set to false to enable non-multipart XHR uploads:
              multipart: true,
              // To upload large files in smaller chunks, set the following option
              // to a preferred maximum chunk size. If set to 0, null or undefined,
              // or the browser does not support the required Blob API, files will
              // be uploaded as a whole.
              maxChunkSize: undefined,
              // When a non-multipart upload or a chunked multipart upload has been
              // aborted, this option can be used to resume the upload by setting
              // it to the size of the already uploaded bytes. This option is most
              // useful when modifying the options object inside of the "add" or
              // "send" callbacks, as the options are cloned for each file upload.
              uploadedBytes: undefined,
              // By default, failed (abort or error) file uploads are removed from the
              // global progress calculation. Set the following option to false to
              // prevent recalculating the global progress data:
              recalculateProgress: true,
              // Interval in milliseconds to calculate and trigger progress events:
              progressInterval: 100,
              // Interval in milliseconds to calculate progress bitrate:
              bitrateInterval: 500,
              // By default, uploads are started automatically when adding files:
              autoUpload: true,
  
              // Error and info messages:
              messages: {
                  uploadedBytes: 'Uploaded bytes exceed file size'
              },
  
              // Translation function, gets the message key to be translated
              // and an object with context specific data as arguments:
              i18n: function(message, context) {
                  message = this.messages[message] || message.toString();
                  if (context) {
                      langx.each(context, function(key, value) {
                          message = message.replace('{' + key + '}', value);
                      });
                  }
                  return message;
              },
  
              // Additional form data to be sent along with the file uploads can be set
              // using this option, which accepts an array of objects with name and
              // value properties, a function returning such an array, a FormData
              // object (for XHR file uploads), or a simple object.
              // The form of the first fileInput is given as parameter to the function:
              formData: function(form) {
                  return form.serializeArray();
              },
  
              // The add callback is invoked as soon as files are added to the fileupload
              // widget (via file input selection, drag & drop, paste or add API call).
              // If the singleFileUploads option is enabled, this callback will be
              // called once for each file in the selection for XHR file uploads, else
              // once for each file selection.
              //
              // The upload starts when the submit method is invoked on the data parameter.
              // The data object contains a files property holding the added files
              // and allows you to override plugin options as well as define ajax settings.
              //
              // Listeners for this callback can also be bound the following way:
              // .bind('fileuploadadd', func);
              //
              // data.submit() returns a Promise object and allows to attach additional
              // handlers using jQuery's Deferred callbacks:
              // data.submit().done(func).fail(func).always(func);
              add: function(e, data) {
                  if (e.isDefaultPrevented()) {
                      return false;
                  }
                  if (data.autoUpload || (data.autoUpload !== false &&
                          $(this).fileupload('option', 'autoUpload'))) {
                      data.process().done(function() {
                          data.submit();
                      });
                  }
              },
  
              // Other callbacks:
  
              // Callback for the submit event of each file upload:
              // submit: function (e, data) {}, // .bind('fileuploadsubmit', func);
  
              // Callback for the start of each file upload request:
              // send: function (e, data) {}, // .bind('fileuploadsend', func);
  
              // Callback for successful uploads:
              // done: function (e, data) {}, // .bind('fileuploaddone', func);
  
              // Callback for failed (abort or error) uploads:
              // fail: function (e, data) {}, // .bind('fileuploadfail', func);
  
              // Callback for completed (success, abort or error) requests:
              // always: function (e, data) {}, // .bind('fileuploadalways', func);
  
              // Callback for upload progress events:
              // progress: function (e, data) {}, // .bind('fileuploadprogress', func);
  
              // Callback for global upload progress events:
              // progressall: function (e, data) {}, // .bind('fileuploadprogressall', func);
  
              // Callback for uploads start, equivalent to the global ajaxStart event:
              // start: function (e) {}, // .bind('fileuploadstart', func);
  
              // Callback for uploads stop, equivalent to the global ajaxStop event:
              // stop: function (e) {}, // .bind('fileuploadstop', func);
  
              // Callback for change events of the fileInput(s):
              // change: function (e, data) {}, // .bind('fileuploadchange', func);
  
              // Callback for paste events to the pasteZone(s):
              // paste: function (e, data) {}, // .bind('fileuploadpaste', func);
  
              // Callback for drop events of the dropZone(s):
              // drop: function (e, data) {}, // .bind('fileuploaddrop', func);
  
              // Callback for dragover events of the dropZone(s):
              // dragover: function (e) {}, // .bind('fileuploaddragover', func);
  
              // Callback for the start of each chunk upload request:
              // chunksend: function (e, data) {}, // .bind('fileuploadchunksend', func);
  
              // Callback for successful chunk uploads:
              // chunkdone: function (e, data) {}, // .bind('fileuploadchunkdone', func);
  
              // Callback for failed (abort or error) chunk uploads:
              // chunkfail: function (e, data) {}, // .bind('fileuploadchunkfail', func);
  
              // Callback for completed (success, abort or error) chunk upload requests:
              // chunkalways: function (e, data) {}, // .bind('fileuploadchunkalways', func);
  
              // The plugin options are used as settings object for the ajax calls.
              // The following are jQuery ajax settings required for the file uploads:
              processData: false,
              contentType: false,
              cache: false
          }, params);
  
          var blobSlice = function() {
                  var slice = Blob.prototype.slice || Blob.prototype.webkitSlice || Blob.prototype.mozSlice;
                  return slice.apply(this, arguments);
              },
              ajax = function(data) {
                  return langx.Xhr.request(data.url, data);
              };
  
          function initDataSettings(o) {
              o.type = o.type || "POST";
  
              if (!chunkedUpload(o, true)) {
                  if (!o.data) {
                      initXHRData(o);
                  }
                  //initProgressListener(o);
              }
          }
  
          function initXHRData(o) {
              var that = this,
                  formData,
                  file = o.files[0],
                  // Ignore non-multipart setting if not supported:
                  multipart = o.multipart,
                  paramName = langx.type(o.paramName) === 'array' ?
                  o.paramName[0] : o.paramName;
  
              o.headers = langx.mixin({}, o.headers);
              if (o.contentRange) {
                  o.headers['Content-Range'] = o.contentRange;
              }
              if (!multipart) {
                  o.headers['Content-Disposition'] = 'attachment; filename="' +
                      encodeURI(file.name) + '"';
                  o.contentType = file.type || 'application/octet-stream';
                  o.data = o.blob || file;
              } else {
                  formData = new FormData();
                  if (o.blob) {
                      formData.append(paramName, o.blob, file.name);
                  } else {
                      langx.each(o.files, function(index, file) {
                          // This check allows the tests to run with
                          // dummy objects:
                          formData.append(
                              (langx.type(o.paramName) === 'array' &&
                                  o.paramName[index]) || paramName,
                              file,
                              file.uploadName || file.name
                          );
                      });
                  }
                  o.data = formData;
              }
              // Blob reference is not needed anymore, free memory:
              o.blob = null;
          }
  
          function getTotal(files) {
              var total = 0;
              langx.each(files, function(index, file) {
                  total += file.size || 1;
              });
              return total;
          }
  
          function getUploadedBytes(jqXHR) {
              var range = jqXHR.getResponseHeader('Range'),
                  parts = range && range.split('-'),
                  upperBytesPos = parts && parts.length > 1 &&
                  parseInt(parts[1], 10);
              return upperBytesPos && upperBytesPos + 1;
          }
  
          function initProgressObject(obj) {
              var progress = {
                  loaded: 0,
                  total: 0,
                  bitrate: 0
              };
              if (obj._progress) {
                  langx.mixin(obj._progress, progress);
              } else {
                  obj._progress = progress;
              }
          }
  
          function BitrateTimer() {
              this.timestamp = ((Date.now) ? Date.now() : (new Date()).getTime());
              this.loaded = 0;
              this.bitrate = 0;
              this.getBitrate = function(now, loaded, interval) {
                  var timeDiff = now - this.timestamp;
                  if (!this.bitrate || !interval || timeDiff > interval) {
                      this.bitrate = (loaded - this.loaded) * (1000 / timeDiff) * 8;
                      this.loaded = loaded;
                      this.timestamp = now;
                  }
                  return this.bitrate;
              };
          }
  
          function chunkedUpload(options, testOnly) {
              options.uploadedBytes = options.uploadedBytes || 0;
              var that = this,
                  file = options.files[0],
                  fs = file.size,
                  ub = options.uploadedBytes,
                  mcs = options.maxChunkSize || fs,
                  slice = blobSlice,
                  dfd = new Deferred(),
                  promise = dfd.promise,
                  jqXHR,
                  upload;
              if (!(slice && (ub || mcs < fs)) ||
                  options.data) {
                  return false;
              }
              if (testOnly) {
                  return true;
              }
              if (ub >= fs) {
                  file.error = options.i18n('uploadedBytes');
                  return this._getXHRPromise(
                      false,
                      options.context, [null, 'error', file.error]
                  );
              }
              // The chunk upload method:
              upload = function() {
                  // Clone the options object for each chunk upload:
                  var o = langx.mixin({}, options),
                      currentLoaded = o._progress.loaded;
                  o.blob = slice.call(
                      file,
                      ub,
                      ub + mcs,
                      file.type
                  );
                  // Store the current chunk size, as the blob itself
                  // will be dereferenced after data processing:
                  o.chunkSize = o.blob.size;
                  // Expose the chunk bytes position range:
                  o.contentRange = 'bytes ' + ub + '-' +
                      (ub + o.chunkSize - 1) + '/' + fs;
                  // Process the upload data (the blob and potential form data):
                  initXHRData(o);
                  // Add progress listeners for this chunk upload:
                  //initProgressListener(o);
                  jqXHR = $.ajax(o).done(function(result, textStatus, jqXHR) {
                          ub = getUploadedBytes(jqXHR) ||
                              (ub + o.chunkSize);
                          // Create a progress event if no final progress event
                          // with loaded equaling total has been triggered
                          // for this chunk:
                          if (currentLoaded + o.chunkSize - o._progress.loaded) {
                              dfd.progress({
                                  lengthComputable: true,
                                  loaded: ub - o.uploadedBytes,
                                  total: ub - o.uploadedBytes
                              });
                          }
                          options.uploadedBytes = o.uploadedBytes = ub;
                          o.result = result;
                          o.textStatus = textStatus;
                          o.jqXHR = jqXHR;
                          //that._trigger('chunkdone', null, o);
                          //that._trigger('chunkalways', null, o);
                          if (ub < fs) {
                              // File upload not yet complete,
                              // continue with the next chunk:
                              upload();
                          } else {
                              dfd.resolveWith(
                                  o.context, [result, textStatus, jqXHR]
                              );
                          }
                      })
                      .fail(function(jqXHR, textStatus, errorThrown) {
                          o.jqXHR = jqXHR;
                          o.textStatus = textStatus;
                          o.errorThrown = errorThrown;
                          //that._trigger('chunkfail', null, o);
                          //that._trigger('chunkalways', null, o);
                          dfd.rejectWith(
                              o.context, [jqXHR, textStatus, errorThrown]
                          );
                      });
              };
              //this._enhancePromise(promise);
              promise.abort = function() {
                  return jqXHR.abort();
              };
              upload();
              return promise;
          }
  
          initDataSettings(xoptions);
  
          xoptions._bitrateTimer = new BitrateTimer();
  
          var jqXhr = chunkedUpload(xoptions) || ajax(xoptions);
  
          jqXhr.options = xoptions;
  
          return jqXhr;
      }
  
      var filer = function() {
          return filer;
      };
  
      langx.mixin(filer, {
          dropzone: dropzone,
  
          pastezone: pastezone,
  
          picker: picker,
  
          select: select,
  
          upload: upload,
  
          readFile: function(file, params) {
              params = params || {};
              var d = new Deferred,
                  reader = new FileReader();
  
              reader.onload = function(evt) {
                  d.resolve(evt.target.result);
              };
              reader.onerror = function(e) {
                  var code = e.target.error.code;
                  if (code === 2) {
                      alert('please don\'t open this page using protocol fill:///');
                  } else {
                      alert('error code: ' + code);
                  }
              };
  
              if (params.asArrayBuffer) {
                  reader.readAsArrayBuffer(file);
              } else if (params.asDataUrl) {
                  reader.readAsDataURL(file);
              } else if (params.asText) {
                  reader.readAsText(file);
              } else {
                  reader.readAsArrayBuffer(file);
              }
  
              return d.promise;
          },
  
          writeFile: function(data, name) {
              if (window.navigator.msSaveBlob) {
                  if (langx.isString(data)) {
                      data = dataURItoBlob(data);
                  }
                  window.navigator.msSaveBlob(data, name);
              } else {
                  var a = document.createElement('a');
                  if (data instanceof Blob) {
                      data = langx.URL.createObjectURL(data);
                  }
                  a.href = data;
                  a.setAttribute('download', name || 'noname');
                  a.dispatchEvent(new CustomEvent('click'));
              }
          }
  
      });
  
      return skylark.filer = filer;
  });
  define('skylarkjs/filer',[
      "skylark-utils/filer"
  ], function(filer) {
      return filer;
  });
  
  define('skylarkjs/finder',[
      "skylark-utils/finder"
  ], function(finder) {
      return finder;
  });
  
  define('skylark-utils/fx',[
      "./skylark",
      "./langx",
      "./browser",
      "./geom",
      "./styler",
      "./eventer"
  ], function(skylark, langx, browser, geom, styler, eventer) {
      var animationName,
          animationDuration,
          animationTiming,
          animationDelay,
          transitionProperty,
          transitionDuration,
          transitionTiming,
          transitionDelay,
  
          animationEnd = browser.normalizeCssEvent('AnimationEnd'),
          transitionEnd = browser.normalizeCssEvent('TransitionEnd'),
  
          supportedTransforms = /^((translate|rotate|scale)(X|Y|Z|3d)?|matrix(3d)?|perspective|skew(X|Y)?)$/i,
          transform = browser.css3PropPrefix + "transform",
          cssReset = {};
  
  
      cssReset[animationName = browser.normalizeCssProperty("animation-name")] =
          cssReset[animationDuration = browser.normalizeCssProperty("animation-duration")] =
          cssReset[animationDelay = browser.normalizeCssProperty("animation-delay")] =
          cssReset[animationTiming = browser.normalizeCssProperty("animation-timing-function")] = "";
  
      cssReset[transitionProperty = browser.normalizeCssProperty("transition-property")] =
          cssReset[transitionDuration = browser.normalizeCssProperty("transition-duration")] =
          cssReset[transitionDelay = browser.normalizeCssProperty("transition-delay")] =
          cssReset[transitionTiming = browser.normalizeCssProperty("transition-timing-function")] = "";
  
  
  
      /*   
       * Perform a custom animation of a set of CSS properties.
       * @param {Object} elm  
       * @param {Number or String} properties
       * @param {String} ease
       * @param {Number or String} duration
       * @param {Function} callback
       * @param {Number or String} delay
       */
      function animate(elm, properties, duration, ease, callback, delay) {
          var key,
              cssValues = {},
              cssProperties = [],
              transforms = "",
              that = this,
              endEvent,
              wrappedCallback,
              fired = false,
              hasScrollTop = false,
              resetClipAuto = false;
  
          if (langx.isPlainObject(duration)) {
              ease = duration.easing;
              callback = duration.complete;
              delay = duration.delay;
              duration = duration.duration;
          }
  
          if (langx.isString(duration)) {
              duration = fx.speeds[duration];
          }
          if (duration === undefined) {
              duration = fx.speeds.normal;
          }
          duration = duration / 1000;
          if (fx.off) {
              duration = 0;
          }
  
          if (langx.isFunction(ease)) {
              callback = ease;
              eace = "swing";
          } else {
              ease = ease || "swing";
          }
  
          if (delay) {
              delay = delay / 1000;
          } else {
              delay = 0;
          }
  
          if (langx.isString(properties)) {
              // keyframe animation
              cssValues[animationName] = properties;
              cssValues[animationDuration] = duration + "s";
              cssValues[animationTiming] = ease;
              endEvent = animationEnd;
          } else {
              // CSS transitions
              for (key in properties) {
                  var v = properties[key];
                  if (supportedTransforms.test(key)) {
                      transforms += key + "(" + v + ") ";
                  } else {
                      if (key === "scrollTop") {
                          hasScrollTop = true;
                      }
                      if (key == "clip" && langx.isPlainObject(v)) {
                          cssValues[key] = "rect(" + v.top+"px,"+ v.right +"px,"+ v.bottom +"px,"+ v.left+"px)";
                          if (styler.css(elm,"clip") == "auto") {
                              var size = geom.size(elm);
                              styler.css(elm,"clip","rect("+"0px,"+ size.width +"px,"+ size.height +"px,"+"0px)");  
                              resetClipAuto = true;
                          }
  
                      } else {
                          cssValues[key] = v;
                      }
                      cssProperties.push(langx.dasherize(key));
                  }
              }
              endEvent = transitionEnd;
          }
  
          if (transforms) {
              cssValues[transform] = transforms;
              cssProperties.push(transform);
          }
  
          if (duration > 0 && langx.isPlainObject(properties)) {
              cssValues[transitionProperty] = cssProperties.join(", ");
              cssValues[transitionDuration] = duration + "s";
              cssValues[transitionDelay] = delay + "s";
              cssValues[transitionTiming] = ease;
          }
  
          wrappedCallback = function(event) {
              fired = true;
              if (event) {
                  if (event.target !== event.currentTarget) {
                      return // makes sure the event didn't bubble from "below"
                  }
                  eventer.off(event.target, endEvent, wrappedCallback)
              } else {
                  eventer.off(elm, animationEnd, wrappedCallback) // triggered by setTimeout
              }
              styler.css(elm, cssReset);
              if (resetClipAuto) {
   //               styler.css(elm,"clip","auto");
              }
              callback && callback.call(this);
          };
  
          if (duration > 0) {
              eventer.on(elm, endEvent, wrappedCallback);
              // transitionEnd is not always firing on older Android phones
              // so make sure it gets fired
              langx.debounce(function() {
                  if (fired) {
                      return;
                  }
                  wrappedCallback.call(that);
              }, ((duration + delay) * 1000) + 25)();
          }
  
          // trigger page reflow so new elements can animate
          elm.clientLeft;
  
          styler.css(elm, cssValues);
  
          if (duration <= 0) {
              langx.debounce(function() {
                  if (fired) {
                      return;
                  }
                  wrappedCallback.call(that);
              }, 0)();
          }
  
          if (hasScrollTop) {
              scrollToTop(elm, properties["scrollTop"], duration, callback);
          }
  
          return this;
      }
  
      /*   
       * Display an element.
       * @param {Object} elm  
       * @param {String} speed
       * @param {Function} callback
       */
      function show(elm, speed, callback) {
          styler.show(elm);
          if (speed) {
              if (!callback && langx.isFunction(speed)) {
                  callback = speed;
                  speed = "normal";
              }
              styler.css(elm, "opacity", 0)
              animate(elm, { opacity: 1, scale: "1,1" }, speed, callback);
          }
          return this;
      }
  
  
      /*   
       * Hide an element.
       * @param {Object} elm  
       * @param {String} speed
       * @param {Function} callback
       */
      function hide(elm, speed, callback) {
          if (speed) {
              if (!callback && langx.isFunction(speed)) {
                  callback = speed;
                  speed = "normal";
              }
              animate(elm, { opacity: 0, scale: "0,0" }, speed, function() {
                  styler.hide(elm);
                  if (callback) {
                      callback.call(elm);
                  }
              });
          } else {
              styler.hide(elm);
          }
          return this;
      }
  
      /*   
       * Set the vertical position of the scroll bar for an element.
       * @param {Object} elm  
       * @param {Number or String} pos
       * @param {Number or String} speed
       * @param {Function} callback
       */
      function scrollToTop(elm, pos, speed, callback) {
          var scrollFrom = parseInt(elm.scrollTop),
              i = 0,
              runEvery = 5, // run every 5ms
              freq = speed * 1000 / runEvery,
              scrollTo = parseInt(pos);
  
          var interval = setInterval(function() {
              i++;
  
              if (i <= freq) elm.scrollTop = (scrollTo - scrollFrom) / freq * i + scrollFrom;
  
              if (i >= freq + 1) {
                  clearInterval(interval);
                  if (callback) langx.debounce(callback, 1000)();
              }
          }, runEvery);
      }
  
      /*   
       * Display or hide an element.
       * @param {Object} elm  
       * @param {Number or String} speed
       * @param {Function} callback
       */
      function toggle(elm, speed, callback) {
          if (styler.isInvisible(elm)) {
              show(elm, speed, callback);
          } else {
              hide(elm, speed, callback);
          }
          return this;
      }
  
      /*   
       * Adjust the opacity of an element.
       * @param {Object} elm  
       * @param {Number or String} speed
       * @param {Number or String} opacity
       * @param {String} easing
       * @param {Function} callback
       */
      function fadeTo(elm, speed, opacity, easing, callback) {
          animate(elm, { opacity: opacity }, speed, easing, callback);
          return this;
      }
  
  
      /*   
       * Display an element by fading them to opaque.
       * @param {Object} elm  
       * @param {Number or String} speed
       * @param {String} easing
       * @param {Function} callback
       */
      function fadeIn(elm, speed, easing, callback) {
          var target = styler.css(elm, "opacity");
          if (target > 0) {
              styler.css(elm, "opacity", 0);
          } else {
              target = 1;
          }
          styler.show(elm);
  
          fadeTo(elm, speed, target, easing, callback);
  
          return this;
      }
  
      /*   
       * Hide an element by fading them to transparent.
       * @param {Object} elm  
       * @param {Number or String} speed
       * @param {String} easing
       * @param {Function} callback
       */
      function fadeOut(elm, speed, easing, callback) {
          var _elm = elm,
              complete,
              opacity = styler.css(elm,"opacity"),
              options = {};
  
          if (langx.isPlainObject(speed)) {
              options.easing = speed.easing;
              options.duration = speed.duration;
              complete = speed.complete;
          } else {
              options.duration = speed;
              if (callback) {
                  complete = callback;
                  options.easing = easing;
              } else {
                  complete = easing;
              }
          }
          options.complete = function() {
              styler.css(elm,"opacity",opacity);
              styler.hide(elm);
              if (complete) {
                  complete.call(elm);
              }
          }
  
          fadeTo(elm, options, 0);
  
          return this;
      }
  
      /*   
       * Display or hide an element by animating its opacity.
       * @param {Object} elm  
       * @param {Number or String} speed
       * @param {String} ceasing
       * @param {Function} callback
       */
      function fadeToggle(elm, speed, ceasing, allback) {
          if (styler.isInvisible(elm)) {
              fadeIn(elm, speed, easing, callback);
          } else {
              fadeOut(elm, speed, easing, callback);
          }
          return this;
      }
  
      /*   
       * Display an element with a sliding motion.
       * @param {Object} elm  
       * @param {Number or String} duration
       * @param {Function} callback
       */
      function slideDown(elm, duration, callback) {
  
          // get the element position to restore it then
          var position = styler.css(elm, 'position');
  
          // show element if it is hidden
          show(elm);
  
          // place it so it displays as usually but hidden
          styler.css(elm, {
              position: 'absolute',
              visibility: 'hidden'
          });
  
          // get naturally height, margin, padding
          var marginTop = styler.css(elm, 'margin-top');
          var marginBottom = styler.css(elm, 'margin-bottom');
          var paddingTop = styler.css(elm, 'padding-top');
          var paddingBottom = styler.css(elm, 'padding-bottom');
          var height = styler.css(elm, 'height');
  
          // set initial css for animation
          styler.css(elm, {
              position: position,
              visibility: 'visible',
              overflow: 'hidden',
              height: 0,
              marginTop: 0,
              marginBottom: 0,
              paddingTop: 0,
              paddingBottom: 0
          });
  
          // animate to gotten height, margin and padding
          animate(elm, {
              height: height,
              marginTop: marginTop,
              marginBottom: marginBottom,
              paddingTop: paddingTop,
              paddingBottom: paddingBottom
          }, {
              duration: duration,
              complete: function() {
                  if (callback) {
                      callback.apply(elm);
                  }
              }
          });
  
          return this;
      };
  
      /*   
       * Hide an element with a sliding motion.
       * @param {Object} elm  
       * @param {Number or String} duration
       * @param {Function} callback
       */
      function slideUp(elm, duration, callback) {
          // active the function only if the element is visible
          if (geom.height(elm) > 0) {
  
              // get the element position to restore it then
              var position = styler.css(elm, 'position');
  
              // get the element height, margin and padding to restore them then
              var height = styler.css(elm, 'height');
              var marginTop = styler.css(elm, 'margin-top');
              var marginBottom = styler.css(elm, 'margin-bottom');
              var paddingTop = styler.css(elm, 'padding-top');
              var paddingBottom = styler.css(elm, 'padding-bottom');
  
              // set initial css for animation
              styler.css(elm, {
                  visibility: 'visible',
                  overflow: 'hidden',
                  height: height,
                  marginTop: marginTop,
                  marginBottom: marginBottom,
                  paddingTop: paddingTop,
                  paddingBottom: paddingBottom
              });
  
              // animate element height, margin and padding to zero
              animate(elm, {
                  height: 0,
                  marginTop: 0,
                  marginBottom: 0,
                  paddingTop: 0,
                  paddingBottom: 0
              }, {
                  // callback : restore the element position, height, margin and padding to original values
                  duration: duration,
                  queue: false,
                  complete: function() {
                      hide(elm);
                      styler.css(elm, {
                          visibility: 'visible',
                          overflow: 'hidden',
                          height: height,
                          marginTop: marginTop,
                          marginBottom: marginBottom,
                          paddingTop: paddingTop,
                          paddingBottom: paddingBottom
                      });
                      if (callback) {
                          callback.apply(elm);
                      }
                  }
              });
          }
          return this;
      };
  
  
      /*   
       * Display or hide an element with a sliding motion.
       * @param {Object} elm  
       * @param {Number or String} duration
       * @param {Function} callback
       */
      function slideToggle(elm, duration, callback) {
  
          // if the element is hidden, slideDown !
          if (geom.height(elm) == 0) {
              slideDown(elm, duration, callback);
          }
          // if the element is visible, slideUp !
          else {
              slideUp(elm, duration, callback);
          }
          return this;
      };
  
  
      function fx() {
          return fx;
      }
  
      langx.mixin(fx, {
          off: false,
  
          speeds: {
              normal: 400,
              fast: 200,
              slow: 600
          },
  
          animate: animate,
          fadeIn: fadeIn,
          fadeOut: fadeOut,
          fadeTo: fadeTo,
          fadeToggle: fadeToggle,
          hide: hide,
          scrollToTop: scrollToTop,
  
          slideDown: slideDown,
          slideToggle: slideToggle,
          slideUp: slideUp,
          show: show,
          toggle: toggle
      });
  
      return skylark.fx = fx;
  });
  define('skylarkjs/fx',[
      "skylark-utils/fx"
  ], function(fx) {
      return fx;
  });
  
  define('skylarkjs/geom',[
      "skylark-utils/geom"
  ], function(geom) {
      return geom;
  });
  
  define('skylark-utils/transforms',[
      "./skylark",
      "./langx",
      "./browser",
      "./datax",
      "./styler"
  ], function(skylark,langx,browser,datax,styler) {
    var css3Transform = browser.normalizeCssProperty("transform");
  
    function getMatrix(radian, x, y) {
      var Cos = Math.cos(radian), Sin = Math.sin(radian);
      return {
        M11: Cos * x, 
        M12: -Sin * y,
        M21: Sin * x, 
        M22: Cos * y
      };
    }
  
    function getZoom(scale, zoom) {
        return scale > 0 && scale > -zoom ? zoom :
          scale < 0 && scale < zoom ? -zoom : 0;
    }
  
      function change(el,d) {
        var matrix = getMatrix(d.radian, d.y, d.x);
        styler.css(el,css3Transform, "matrix("
          + matrix.M11.toFixed(16) + "," + matrix.M21.toFixed(16) + ","
          + matrix.M12.toFixed(16) + "," + matrix.M22.toFixed(16) + ", 0, 0)"
        );      
    }
  
    function transformData(el,d) {
      if (d) {
        datax.data(el,"transform",d);
      } else {
        d = datax.data(el,"transform") || {};
        d.radian = d.radian || 0;
        d.x = d.x || 1;
        d.y = d.y || 1;
        d.zoom = d.zoom || 1;
        return d;     
      }
    }
  
    var calcs = {
      //Vertical flip
      vertical : function (d) {
          d.radian = Math.PI - d.radian; 
          d.y *= -1;
      },
  
     //Horizontal flip
      horizontal : function (d) {
          d.radian = Math.PI - d.radian; 
          d.x *= -1;
      },
  
      //Rotate according to angle
      rotate : function (d,degress) {
          d.radian = degress * Math.PI / 180;; 
      },
  
      //Turn left 90 degrees
      left : function (d) {
          d.radian -= Math.PI / 2; 
      },
  
      //Turn right 90 degrees
      right : function (d) {
          d.radian += Math.PI / 2; 
      },
   
      //zoom
      scale: function (d,zoom) {
          var hZoom = getZoom(d.y, zoom), vZoom = getZoom(d.x, zoom);
          if (hZoom && vZoom) {
            d.y += hZoom; 
            d.x += vZoom;
          }
      }, 
  
      //zoom in
      zoomin: function (d) { 
        calcs.scale(d,0.1); 
      },
      
      //zoom out
      zoomout: function (d) { 
        calcs.scale(d,-0.1); 
      }
  
    };
    
    
    function _createApiMethod(calcFunc) {
      return function() {
        var args = langx.makeArray(arguments),
          el = args.shift(),
            d = transformData(el);
          args.unshift(d);
          calcFunc.apply(this,args)
          change(el,d);
          transformData(el,d);
      }
    }
    
    function transforms() {
      return transforms;
    }
  
    ["vertical","horizontal","rotate","left","right","scale","zoom","zoomin","zoomout"].forEach(function(name){
      transforms[name] = _createApiMethod(calcs[name]);
    });
  
    langx.mixin(transforms, {
      reset : function(el) {
        var d = {
          x : 1,
          y : 1,
          radian : 0,
        }
        change(el,d);
        transformData(el,d);
      }
    });
  
  
    return skylark.transforms = transforms;
  });
  
  define('skylark-utils/query',[
      "./skylark",
      "./langx",
      "./noder",
      "./datax",
      "./eventer",
      "./finder",
      "./geom",
      "./styler",
      "./fx"
  ], function(skylark, langx, noder, datax, eventer, finder, geom, styler, fx) {
      var some = Array.prototype.some,
          push = Array.prototype.push,
          every = Array.prototype.every,
          concat = Array.prototype.concat,
          slice = Array.prototype.slice,
          map = Array.prototype.map,
          filter = Array.prototype.filter,
          forEach = Array.prototype.forEach,
          indexOf = Array.prototype.indexOf,
          sort = Array.prototype.sort,
          isQ;
  
      var rquickExpr = /^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/;
  
      var funcArg = langx.funcArg,
          isArrayLike = langx.isArrayLike,
          isString = langx.isString,
          uniq = langx.uniq,
          isFunction = langx.isFunction;
  
      var type = langx.type,
          isArray = langx.isArray,
  
          isWindow = langx.isWindow,
  
          isDocument = langx.isDocument,
  
          isObject = langx.isObject,
  
          isPlainObject = langx.isPlainObject,
  
          compact = langx.compact,
  
          flatten = langx.flatten,
  
          camelCase = langx.camelCase,
  
          dasherize = langx.dasherize,
          children = finder.children;
  
      function wrapper_map(func, context) {
          return function() {
              var self = this,
                  params = slice.call(arguments);
              var result = $.map(self, function(elem, idx) {
                  return func.apply(context, [elem].concat(params));
              });
              return $(uniq(result));
          }
      }
  
      function wrapper_selector(func, context, last) {
          return function(selector) {
              var self = this,
                  params = slice.call(arguments);
              var result = this.map(function(idx, elem) {
                  // if (elem.nodeType == 1) {
                  if (elem.querySelector) {
                      return func.apply(context, last ? [elem] : [elem, selector]);
                  }
              });
              if (last && selector) {
                  return result.filter(selector);
              } else {
                  return result;
              }
          }
      }
  
      function wrapper_selector_until(func, context, last) {
          return function(util, selector) {
              var self = this,
                  params = slice.call(arguments);
              if (selector === undefined) {
                  selector = util;
                  util = undefined;
              }
              var result = this.map(function(idx, elem) {
                  // if (elem.nodeType == 1) {
                  if (elem.querySelector) {
                      return func.apply(context, last ? [elem, util] : [elem, selector, util]);
                  }
              });
              if (last && selector) {
                  return result.filter(selector);
              } else {
                  return result;
              }
          }
      }
  
  
      function wrapper_every_act(func, context) {
          return function() {
              var self = this,
                  params = slice.call(arguments);
              this.each(function(idx) {
                  func.apply(context, [this].concat(params));
              });
              return self;
          }
      }
  
      function wrapper_every_act_firstArgFunc(func, context, oldValueFunc) {
          return function(arg1) {
              var self = this,
                  params = slice.call(arguments);
              forEach.call(self, function(elem, idx) {
                  var newArg1 = funcArg(elem, arg1, idx, oldValueFunc(elem));
                  func.apply(context, [elem, arg1].concat(params.slice(1)));
              });
              return self;
          }
      }
  
      function wrapper_some_chk(func, context) {
          return function() {
              var self = this,
                  params = slice.call(arguments);
              return some.call(self, function(elem) {
                  return func.apply(context, [elem].concat(params));
              });
          }
      }
  
      function wrapper_name_value(func, context, oldValueFunc) {
          return function(name, value) {
              var self = this,
                  params = slice.call(arguments);
  
              if (langx.isPlainObject(name) || langx.isDefined(value)) {
                  forEach.call(self, function(elem, idx) {
                      var newValue;
                      if (oldValueFunc) {
                          newValue = funcArg(elem, value, idx, oldValueFunc(elem, name));
                      } else {
                          newValue = value
                      }
                      func.apply(context, [elem].concat(params));
                  });
                  return self;
              } else {
                  if (self[0]) {
                      return func.apply(context, [self[0], name]);
                  }
              }
  
          }
      }
  
      function wrapper_value(func, context, oldValueFunc) {
          return function(value) {
              var self = this;
  
              if (langx.isDefined(value)) {
                  forEach.call(self, function(elem, idx) {
                      var newValue;
                      if (oldValueFunc) {
                          newValue = funcArg(elem, value, idx, oldValueFunc(elem));
                      } else {
                          newValue = value
                      }
                      func.apply(context, [elem, newValue]);
                  });
                  return self;
              } else {
                  if (self[0]) {
                      return func.apply(context, [self[0]]);
                  }
              }
  
          }
      }
  
      var NodeList = langx.klass({
          klassName: "SkNodeList",
          init: function(selector, context) {
              var self = this,
                  match, nodes, node, props;
  
              if (selector) {
                  self.context = context = context || noder.doc();
  
                  if (isString(selector)) {
                      // a html string or a css selector is expected
                      self.selector = selector;
  
                      if (selector.charAt(0) === "<" && selector.charAt(selector.length - 1) === ">" && selector.length >= 3) {
                          match = [null, selector, null];
                      } else {
                          match = rquickExpr.exec(selector);
                      }
  
                      if (match) {
                          if (match[1]) {
                              // if selector is html
                              nodes = noder.createFragment(selector);
  
                              if (langx.isPlainObject(context)) {
                                  props = context;
                              }
  
                          } else {
                              node = finder.byId(match[2], noder.ownerDoc(context));
  
                              if (node) {
                                  // if selector is id
                                  nodes = [node];
                              }
  
                          }
                      } else {
                          // if selector is css selector
                          if (langx.isString(context)) {
                              context = finder.find(context);
                          }
  
                          nodes = finder.descendants(context, selector);
                      }
                  } else {
                      if (isArray(selector)) {
                          // a dom node array is expected
                          nodes = selector;
                      } else {
                          // a dom node is expected
                          nodes = [selector];
                      }
                      //self.add(selector, false);
                  }
              }
  
  
              if (nodes) {
  
                  push.apply(self, nodes);
  
                  if (props) {
                      for ( var name  in props ) {
                          // Properties of context are called as methods if possible
                          if ( langx.isFunction( this[ name ] ) ) {
                              this[ name ]( props[ name ] );
                          } else {
                              this.attr( name, props[ name ] );
                          }
                      }
                  }
              }
  
              return self;
          }
      });
  
      var query = (function() {
          isQ = function(object) {
              return object instanceof NodeList;
          }
          init = function(selector, context) {
              return new NodeList(selector, context);
          }
  
          var $ = function(selector, context) {
              if (isFunction(selector)) {
                  eventer.ready(function() {
                      selector($);
                  });
              } else if (isQ(selector)) {
                  return selector;
              } else {
                  if (context && isQ(context) && isString(selector)) {
                      return context.find(selector);
                  }
                  return init(selector, context);
              }
          };
  
          $.fn = NodeList.prototype;
          langx.mixin($.fn, {
              // `map` and `slice` in the jQuery API work differently
              // from their array counterparts
              length : 0,
  
              map: function(fn) {
                  return $(uniq(langx.map(this, function(el, i) {
                      return fn.call(el, i, el)
                  })));
              },
  
              slice: function() {
                  return $(slice.apply(this, arguments))
              },
  
              forEach: function() {
                  return forEach.apply(this,arguments);
              },
  
              get: function(idx) {
                  return idx === undefined ? slice.call(this) : this[idx >= 0 ? idx : idx + this.length]
              },
  
              indexOf: function() {
                  return indexOf.apply(this,arguments);
              },
  
              sort : function() {
                  return sort.apply(this,arguments);
              },
  
              toArray: function() {
                  return slice.call(this);
              },
  
              size: function() {
                  return this.length
              },
  
              remove: wrapper_every_act(noder.remove, noder),
  
              each: function(callback) {
                  langx.each(this, callback);
                  return this;
              },
  
              filter: function(selector) {
                  if (isFunction(selector)) return this.not(this.not(selector))
                  return $(filter.call(this, function(element) {
                      return finder.matches(element, selector)
                  }))
              },
  
              add: function(selector, context) {
                  return $(uniq(this.toArray().concat($(selector, context).toArray())));
              },
  
              is: function(selector) {
                  if (this.length > 0) {
                      var self = this;
                      if (langx.isString(selector)) {
                          return some.call(self,function(elem) {
                              return finder.matches(elem, selector);
                          });
                      } else if (langx.isArrayLike(selector)) {
                         return some.call(self,function(elem) {
                              return langx.inArray(elem, selector) > -1;
                          });
                      } else if (langx.isHtmlNode(selector)) {
                         return some.call(self,function(elem) {
                              return elem ==  selector;
                          });
                      }
                  }
                  return false;
              },
              
              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) :
                          (isArrayLike(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) ?
                          noder.contains(this, selector) :
                          $(this).find(selector).size()
                  })
              },
  
              eq: function(idx) {
                  return idx === -1 ? this.slice(idx) : this.slice(idx, +idx + 1);
              },
  
              first: function() {
                  return this.eq(0);
              },
  
              last: function() {
                  return this.eq(-1);
              },
  
              find: wrapper_selector(finder.descendants, finder),
  
              closest: wrapper_selector(finder.closest, finder),
              /*
                          closest: function(selector, context) {
                              var node = this[0],
                                  collection = false
                              if (typeof selector == 'object') collection = $(selector)
                              while (node && !(collection ? collection.indexOf(node) >= 0 : finder.matches(node, selector)))
                                  node = node !== context && !isDocument(node) && node.parentNode
                              return $(node)
                          },
              */
  
  
              parents: wrapper_selector(finder.ancestors, finder),
  
              parentsUntil: wrapper_selector_until(finder.ancestors, finder),
  
  
              parent: wrapper_selector(finder.parent, finder),
  
              children: wrapper_selector(finder.children, finder),
  
              contents: wrapper_map(noder.contents, noder),
  
              empty: wrapper_every_act(noder.empty, noder),
  
              // `pluck` is borrowed from Prototype.js
              pluck: function(property) {
                  return langx.map(this, function(el) {
                      return el[property]
                  })
              },
  
              pushStack : function(elms) {
                  var ret = $(elms);
                  ret.prevObject = this;
                  return ret;
              },
              
              show: wrapper_every_act(fx.show, fx),
  
              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(wrappingElement) {
                  if (this[0]) {
                      $(this[0]).before(wrappingElement = $(wrappingElement));
                      var children;
                      // drill down to the inmost element
                      while ((children = wrappingElement.children()).length) {
                          wrappingElement = children.first();
                      }
                      $(wrappingElement).append(this);
                  }
                  return this
              },
  
              wrapInner: function(wrappingElement) {
                  var func = isFunction(wrappingElement)
                  return this.each(function(index) {
                      var self = $(this),
                          contents = self.contents(),
                          dom = func ? wrappingElement.call(this, index) : wrappingElement
                      contents.length ? contents.wrapAll(dom) : self.append(dom)
                  })
              },
  
              unwrap: function(selector) {
                  if (this.parent().children().length === 0) {
                      // remove dom without text
                      this.parent(selector).not("body").each(function() {
                          $(this).replaceWith(document.createTextNode(this.childNodes[0].textContent));
                      });
                  } else {
                      this.parent().each(function() {
                          $(this).replaceWith($(this).children())
                      });
                  }
                  return this
              },
  
              clone: function() {
                  return this.map(function() {
                      return this.cloneNode(true)
                  })
              },
  
              hide: wrapper_every_act(fx.hide, fx),
  
              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 || '*')
              },
  
              prevAll: wrapper_selector(finder.previousSibling, finder),
  
              next: function(selector) {
                  return $(this.pluck('nextElementSibling')).filter(selector || '*')
              },
  
              nextAll: wrapper_selector(finder.nextSiblings, finder),
  
              siblings: wrapper_selector(finder.siblings, finder),
  
              html: wrapper_value(noder.html, noder, noder.html),
  
              text: wrapper_value(datax.text, datax, datax.text),
  
              attr: wrapper_name_value(datax.attr, datax, datax.attr),
  
              removeAttr: wrapper_every_act(datax.removeAttr, datax),
  
              prop: wrapper_name_value(datax.prop, datax, datax.prop),
  
              removeProp: wrapper_every_act(datax.removeProp, datax),
  
              data: wrapper_name_value(datax.data, datax, datax.data),
  
              removeData: wrapper_every_act(datax.removeData, datax),
  
              val: wrapper_value(datax.val, datax, datax.val),
  
              offset: wrapper_value(geom.pagePosition, geom, geom.pagePosition),
  
              style: wrapper_name_value(styler.css, styler),
  
              css: wrapper_name_value(styler.css, styler),
  
              index: function(elem) {
                  if (elem) {
                      return this.indexOf($(elem)[0]);
                  } else {
                      return this.parent().children().indexOf(this[0]);
                  }
              },
  
              //hasClass(name)
              hasClass: wrapper_some_chk(styler.hasClass, styler),
  
              //addClass(name)
              addClass: wrapper_every_act_firstArgFunc(styler.addClass, styler, styler.className),
  
              //removeClass(name)
              removeClass: wrapper_every_act_firstArgFunc(styler.removeClass, styler, styler.className),
  
              //toogleClass(name,when)
              toggleClass: wrapper_every_act_firstArgFunc(styler.toggleClass, styler, styler.className),
  
              scrollTop: wrapper_value(geom.scrollTop, geom),
  
              scrollLeft: wrapper_value(geom.scrollLeft, geom),
  
              position: function() {
                  if (!this.length) return
  
                  var elem = this[0];
  
                  return geom.relativePosition(elem);
              },
  
              offsetParent: wrapper_map(geom.offsetParent, geom)
          });
  
          // for now
          $.fn.detach = $.fn.remove;
  
          $.fn.hover = function(fnOver, fnOut) {
              return this.mouseenter(fnOver).mouseleave(fnOut || fnOver);
          };
  
          $.fn.size = wrapper_value(geom.size, geom);
  
          $.fn.width = wrapper_value(geom.width, geom, geom.width);
  
          $.fn.height = wrapper_value(geom.height, geom, geom.height);
  
          $.fn.clientSize = wrapper_value(geom.clientSize, geom.clientSize);
  
          ['width', 'height'].forEach(function(dimension) {
              var offset, Dimension = dimension.replace(/./, function(m) {
                  return m[0].toUpperCase()
              });
  
              $.fn['outer' + Dimension] = function(margin, value) {
                  if (arguments.length) {
                      if (typeof margin !== 'boolean') {
                          value = margin;
                          margin = false;
                      }
                  } else {
                      margin = false;
                      value = undefined;
                  }
  
                  if (value === undefined) {
                      var el = this[0];
                      if (!el) {
                          return undefined;
                      }
                      var cb = geom.size(el);
                      if (margin) {
                          var me = geom.marginExtents(el);
                          cb.width = cb.width + me.left + me.right;
                          cb.height = cb.height + me.top + me.bottom;
                      }
                      return dimension === "width" ? cb.width : cb.height;
                  } else {
                      return this.each(function(idx, el) {
                          var mb = {};
                          var me = geom.marginExtents(el);
                          if (dimension === "width") {
                              mb.width = value;
                              if (margin) {
                                  mb.width = mb.width - me.left - me.right
                              }
                          } else {
                              mb.height = value;
                              if (margin) {
                                  mb.height = mb.height - me.top - me.bottom;
                              }
                          }
                          geom.size(el, mb);
                      })
  
                  }
              };
          })
  
          $.fn.innerWidth = wrapper_value(geom.clientWidth, geom, geom.clientWidth);
  
          $.fn.innerHeight = wrapper_value(geom.clientHeight, geom, geom.clientHeight);
  
  
          var traverseNode = noder.traverse;
  
          function wrapper_node_operation(func, context, oldValueFunc) {
              return function(html) {
                  var argType, nodes = langx.map(arguments, function(arg) {
                      argType = type(arg)
                      return argType == "object" || argType == "array" || arg == null ?
                          arg : noder.createFragment(arg)
                  });
                  if (nodes.length < 1) {
                      return this
                  }
                  this.each(function(idx) {
                      func.apply(context, [this, nodes, idx > 0]);
                  });
                  return this;
              }
          }
  
  
          $.fn.after = wrapper_node_operation(noder.after, noder);
  
          $.fn.prepend = wrapper_node_operation(noder.prepend, noder);
  
          $.fn.before = wrapper_node_operation(noder.before, noder);
  
          $.fn.append = wrapper_node_operation(noder.append, noder);
  
  
          langx.each( {
              appendTo: "append",
              prependTo: "prepend",
              insertBefore: "before",
              insertAfter: "after",
              replaceAll: "replaceWith"
          }, function( name, original ) {
              $.fn[ name ] = function( selector ) {
                  var elems,
                      ret = [],
                      insert = $( selector ),
                      last = insert.length - 1,
                      i = 0;
  
                  for ( ; i <= last; i++ ) {
                      elems = i === last ? this : this.clone( true );
                      $( insert[ i ] )[ original ]( elems );
  
                      // Support: Android <=4.0 only, PhantomJS 1 only
                      // .get() because push.apply(_, arraylike) throws on ancient WebKit
                      push.apply( ret, elems.get() );
                  }
  
                  return this.pushStack( ret );
              };
          } );
  
  /*
          $.fn.insertAfter = function(html) {
              $(html).after(this);
              return this;
          };
  
          $.fn.insertBefore = function(html) {
              $(html).before(this);
              return this;
          };
  
          $.fn.appendTo = function(html) {
              $(html).append(this);
              return this;
          };
  
          $.fn.prependTo = function(html) {
              $(html).prepend(this);
              return this;
          };
  
          $.fn.replaceAll = function(selector) {
              $(selector).replaceWith(this);
              return this;
          };
  */
          return $;
      })();
  
      (function($) {
          $.fn.on = wrapper_every_act(eventer.on, eventer);
  
          $.fn.off = wrapper_every_act(eventer.off, eventer);
  
          $.fn.trigger = wrapper_every_act(eventer.trigger, eventer);
  
  
          ('focusin focusout focus blur 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(data, callback) {
                  return (0 in arguments) ?
                      this.on(event, data, callback) :
                      this.trigger(event)
              }
          });
  
  
          $.fn.one = function(event, selector, data, callback) {
              if (!langx.isString(selector) && !langx.isFunction(callback)) {
                  callback = data;
                  data = selector;
                  selector = null;
              }
  
              if (langx.isFunction(data)) {
                  callback = data;
                  data = null;
              }
  
              return this.on(event, selector, data, callback, 1)
          };
  
          $.fn.animate = wrapper_every_act(fx.animate, fx);
  
          $.fn.show = wrapper_every_act(fx.show, fx);
          $.fn.hide = wrapper_every_act(fx.hide, fx);
          $.fn.toogle = wrapper_every_act(fx.toogle, fx);
          $.fn.fadeTo = wrapper_every_act(fx.fadeTo, fx);
          $.fn.fadeIn = wrapper_every_act(fx.fadeIn, fx);
          $.fn.fadeOut = wrapper_every_act(fx.fadeOut, fx);
          $.fn.fadeToggle = wrapper_every_act(fx.fadeToggle, fx);
  
          $.fn.slideDown = wrapper_every_act(fx.slideDown, fx);
          $.fn.slideToggle = wrapper_every_act(fx.slideToggle, fx);
          $.fn.slideUp = wrapper_every_act(fx.slideUp, fx);
      })(query);
  
  
      (function($) {
          $.fn.end = function() {
              return this.prevObject || $()
          }
  
          $.fn.andSelf = function() {
              return this.add(this.prevObject || $())
          }
  
          $.fn.addBack = function(selector) {
              if (this.prevObject) {
                  if (selector) {
                      return this.add(this.prevObject.filter(selector));
                  } else {
                      return this.add(this.prevObject);
                  }
              } else {
                  return this;
              }
          }
  
          'filter,add,not,eq,first,last,find,closest,parents,parent,children,siblings'.split(',').forEach(function(property) {
              var fn = $.fn[property]
              $.fn[property] = function() {
                  var ret = fn.apply(this, arguments)
                  ret.prevObject = this
                  return ret
              }
          })
      })(query);
  
  
      (function($) {
          $.fn.query = $.fn.find;
  
          $.fn.place = function(refNode, position) {
              // summary:
              //      places elements of this node list relative to the first element matched
              //      by queryOrNode. Returns the original NodeList. See: `dojo/dom-construct.place`
              // queryOrNode:
              //      may be a string representing any valid CSS3 selector or a DOM node.
              //      In the selector case, only the first matching element will be used
              //      for relative positioning.
              // position:
              //      can be one of:
              //
              //      -   "last" (default)
              //      -   "first"
              //      -   "before"
              //      -   "after"
              //      -   "only"
              //      -   "replace"
              //
              //      or an offset in the childNodes
              if (langx.isString(refNode)) {
                  refNode = finder.descendant(refNode);
              } else if (isQ(refNode)) {
                  refNode = refNode[0];
              }
              return this.each(function(i, node) {
                  switch (position) {
                      case "before":
                          noder.before(refNode, node);
                          break;
                      case "after":
                          noder.after(refNode, node);
                          break;
                      case "replace":
                          noder.replace(refNode, node);
                          break;
                      case "only":
                          noder.empty(refNode);
                          noder.append(refNode, node);
                          break;
                      case "first":
                          noder.prepend(refNode, node);
                          break;
                          // else fallthrough...
                      default: // aka: last
                          noder.append(refNode, node);
                  }
              });
          };
  
          $.fn.addContent = function(content, position) {
              if (content.template) {
                  content = langx.substitute(content.template, content);
              }
              return this.append(content);
          };
  
          $.fn.replaceClass = function(newClass, oldClass) {
              this.removeClass(oldClass);
              this.addClass(newClass);
              return this;
          };
  
      })(query);
  
  
      return skylark.query = query;
  
  });
  define('skylark-utils/images',[
      "./skylark",
      "./langx",
      "./eventer",
      "./noder",
      "./finder",
      "./geom",
      "./styler",
      "./datax",
      "./transforms",
      "./query"
  ], function(skylark,langx,eventer,noder,finder,geom,styler,datax,transforms,$) {
  
    function watch(imgs) {
      if (!langx.isArray(imgs)) {
        imgs = [imgs];
      }
      var totalCount = imgs.length,
          progressedCount = 0,
          successedCount = 0,
          faileredCount = 0,
          d = new langx.Deferred();
  
  
      function complete() {
  
        d.resolve({
          "total" : totalCount,
          "successed" : successedCount,
          "failered" : faileredCount,
          "imgs" : imgs 
        });
      }
  
      function progress(img,isLoaded) {
  
        progressedCount++;
        if (isLoaded) {
          successedCount ++ ; 
        } else {
          faileredCount ++ ;
        }
  
        // progress event
        d.progress({
          "img" : img,
          "isLoaded" : isLoaded,
          "progressed" : progressedCount,
          "total" : totalCount,
          "imgs" : imgs 
        });
  
        // check if completed
        if ( progressedCount == totalCount ) {
          complete();
        }
      }
  
      function check() {
        if (!imgs.length ) {
          complete();
          return;
        }
  
        imgs.forEach(function(img) {
          if (isCompleted(img)) {
            progress(img,isLoaded(img));
          } else {
            eventer.on(img,{
              "load" : function() {
                progress(img,true);
              },
  
              "error" : function() {
                progress(img,false);
              }
            });      
          }
        });
      }
  
      langx.defer(check);
  
      d.promise.totalCount = totalCount;
      return d.promise;
    }
  
  
    function isCompleted(img) {
       return img.complete && img.naturalWidth !== undefined;
    }
  
    function isLoaded(img) {
      return img.complete && img.naturalWidth !== 0;
    }
  
    function loaded(elm,options) {
      var imgs = [];
  
      options = options || {};
  
      function addBackgroundImage (elm1) {
  
        var reURL = /url\((['"])?(.*?)\1\)/gi;
        var matches = reURL.exec( styler.css(elm1,"background-image"));
        var url = matches && matches[2];
        if ( url ) {
          var img = new Image();
          img.src = url;
          imgs.push(img);
        }
      }
  
      // filter siblings
      if ( elm.nodeName == 'IMG' ) {
        imgs.push( elm );
      } else {
        // find children
        var childImgs = finder.findAll(elm,'img');
        // concat childElems to filterFound array
        for ( var i=0; i < childImgs.length; i++ ) {
          imgs.push(childImgs[i]);
        }
  
        // get background image on element
        if ( options.background === true ) {
          addBackgroundImage(elm);
        } else  if ( typeof options.background == 'string' ) {
          var children = finder.findAll(elm, options.background );
          for ( i=0; i < children.length; i++ ) {
            addBackgroundImage( children[i] );
          }
        }
      }
  
      return watch(imgs);
    }
  
    function preload(urls,options) {
        if (langx.isString(urls)) {
          urls = [urls];
        }
        var images = [];
  
        urls.forEach(function(url){
          var img = new Image();
          img.src = url;
          images.push(img);
        });
  
        return watch(images);
    }
  
  
    $.fn.imagesLoaded = function( options ) {
      return loaded(this,options);
    };
  
  
    function viewer(el,options) {
      var img ,
          style = {},
          clientSize = geom.clientSize(el),
          loadedCallback = options.loaded,
          faileredCallback = options.failered;
  
      function onload() {
          styler.css(img,{//居中
            top: (clientSize.height - img.offsetHeight) / 2 + "px",
            left: (clientSize.width - img.offsetWidth) / 2 + "px"
          });
  
          transforms.reset(img);
  
          styler.css(img,{
            visibility: "visible"
          });
  
          if (loadedCallback) {
            loadedCallback();
          }
      }
  
      function onerror() {
  
      }
      function _init() {
        style = styler.css(el,["position","overflow"]);
        if (style.position != "relative" && style.position != "absolute") { 
          styler.css(el,"position", "relative" );
        }
        styler.css(el,"overflow", "hidden" );
  
        img = new Image();
  
        styler.css(img,{
          position: "absolute",
          border: 0, padding: 0, margin: 0, width: "auto", height: "auto",
          visibility: "hidden"
        });
  
        img.onload = onload;
        img.onerror = onerror;
  
        noder.append(el,img);
  
        if (options.url) {
          _load(options.url);
        }
      }
  
      function _load(url) {
          img.style.visibility = "hidden";
          img.src = url;
      }
  
      function _dispose() {
          noder.remove(img);
          styler.css(el,style);
          img = img.onload = img.onerror = null;
      }
  
      _init();
  
      var ret =  {
        load : _load,
        dispose : _dispose
      };
  
      ["vertical","horizontal","rotate","left","right","scale","zoom","zoomin","zoomout","reset"].forEach(
        function(name){
          ret[name] = function() {
            var args = langx.makeArray(arguments);
            args.unshift(img);
            transforms[name].apply(null,args);
          }
        }
      );
  
      return ret;
    }
  
    $.fn.imagesViewer = function( options ) {
      return viewer(this,options);
    };
  
    function images() {
      return images;
    }
  
    images.transform = function (el,options) {
    };
  
    ["vertical","horizontal","rotate","left","right","scale","zoom","zoomin","zoomout","reset"].forEach(
      function(name){
        images.transform[name] = transforms[name];
      }
    );
  
  
    langx.mixin(images, {
      isCompleted : isCompleted,
  
      isLoaded : isLoaded,
  
      loaded : loaded,
  
      preload : preload,
  
      viewer : viewer
    });
  
    return skylark.images = images;
  });
  
  define('skylarkjs/images',[
      "skylark-utils/images"
  ], function(images) {
      return images;
  });
  
  define('skylark-utils/models',[
      "./skylark",
      "./langx"
  ], function(skylark,langx) {
  
    // Map from CRUD to HTTP for our default `Backbone.sync` implementation.
    var methodMap = {
      'create': 'POST',
      'update': 'PUT',
      'patch': 'PATCH',
      'delete': 'DELETE',
      'read': 'GET'
    };
    
  
    var sync = function(method, entity, options) {
      var type = methodMap[method];
  
      // Default options, unless specified.
      langx.defaults(options || (options = {}), {
        emulateHTTP: models.emulateHTTP,
        emulateJSON: models.emulateJSON
      });
  
      // Default JSON-request options.
      var params = {type: type, dataType: 'json'};
  
      // Ensure that we have a URL.
      if (!options.url) {
        params.url = langx.result(entity, 'url') || urlError();
      }
  
      // Ensure that we have the appropriate request data.
      if (options.data == null && entity && (method === 'create' || method === 'update' || method === 'patch')) {
        params.contentType = 'application/json';
        params.data = JSON.stringify(options.attrs || entity.toJSON(options));
      }
  
      // For older servers, emulate JSON by encoding the request into an HTML-form.
      if (options.emulateJSON) {
        params.contentType = 'application/x-www-form-urlencoded';
        params.data = params.data ? {entity: params.data} : {};
      }
  
      // For older servers, emulate HTTP by mimicking the HTTP method with `_method`
      // And an `X-HTTP-Method-Override` header.
      if (options.emulateHTTP && (type === 'PUT' || type === 'DELETE' || type === 'PATCH')) {
        params.type = 'POST';
        if (options.emulateJSON) params.data._method = type;
        var beforeSend = options.beforeSend;
        options.beforeSend = function(xhr) {
          xhr.setRequestHeader('X-HTTP-Method-Override', type);
          if (beforeSend) return beforeSend.apply(this, arguments);
        };
      }
  
      // Don't process data on a non-GET request.
      if (params.type !== 'GET' && !options.emulateJSON) {
        params.processData = false;
      }
  
      // Pass along `textStatus` and `errorThrown` from jQuery.
      var error = options.error;
      options.error = function(xhr, textStatus, errorThrown) {
        options.textStatus = textStatus;
        options.errorThrown = errorThrown;
        if (error) error.call(options.context, xhr, textStatus, errorThrown);
      };
  
      // Make the request, allowing the user to override any Ajax options.
      var xhr = options.xhr = langx.Xhr.request(langx.mixin(params, options));
      entity.trigger('request', entity, xhr, options);
      return xhr;
    };
  
  
    var Entity = langx.Stateful.inherit({
      sync: function() {
        return models.sync.apply(this, arguments);
      },
  
      // Get the HTML-escaped value of an attribute.
      //escape: function(attr) {
      //  return _.escape(this.get(attr));
      //},
  
      // Special-cased proxy to underscore's `_.matches` method.
      matches: function(attrs) {
        return langx.isMatch(this.attributes,attrs);
      },
  
      // Fetch the entity from the server, merging the response with the entity's
      // local attributes. Any changed attributes will trigger a "change" event.
      fetch: function(options) {
        options = langx.mixin({parse: true}, options);
        var entity = this;
        var success = options.success;
        options.success = function(resp) {
          var serverAttrs = options.parse ? entity.parse(resp, options) : resp;
          if (!entity.set(serverAttrs, options)) return false;
          if (success) success.call(options.context, entity, resp, options);
          entity.trigger('sync', entity, resp, options);
        };
        wrapError(this, options);
        return this.sync('read', this, options);
      },
  
      // Set a hash of entity attributes, and sync the entity to the server.
      // If the server returns an attributes hash that differs, the entity's
      // state will be `set` again.
      save: function(key, val, options) {
        // Handle both `"key", value` and `{key: value}` -style arguments.
        var attrs;
        if (key == null || typeof key === 'object') {
          attrs = key;
          options = val;
        } else {
          (attrs = {})[key] = val;
        }
  
        options = langx.mixin({validate: true, parse: true}, options);
        var wait = options.wait;
  
        // If we're not waiting and attributes exist, save acts as
        // `set(attr).save(null, opts)` with validation. Otherwise, check if
        // the entity will be valid when the attributes, if any, are set.
        if (attrs && !wait) {
          if (!this.set(attrs, options)) return false;
        } else if (!this._validate(attrs, options)) {
          return false;
        }
  
        // After a successful server-side save, the client is (optionally)
        // updated with the server-side state.
        var entity = this;
        var success = options.success;
        var attributes = this.attributes;
        options.success = function(resp) {
          // Ensure attributes are restored during synchronous saves.
          entity.attributes = attributes;
          var serverAttrs = options.parse ? entity.parse(resp, options) : resp;
          if (wait) serverAttrs = langx.mixin({}, attrs, serverAttrs);
          if (serverAttrs && !entity.set(serverAttrs, options)) return false;
          if (success) success.call(options.context, entity, resp, options);
          entity.trigger('sync', entity, resp, options);
        };
        wrapError(this, options);
  
        // Set temporary attributes if `{wait: true}` to properly find new ids.
        if (attrs && wait) this.attributes = langx.mixin({}, attributes, attrs);
  
        var method = this.isNew() ? 'create' : (options.patch ? 'patch' : 'update');
        if (method === 'patch' && !options.attrs) options.attrs = attrs;
        var xhr = this.sync(method, this, options);
  
        // Restore attributes.
        this.attributes = attributes;
  
        return xhr;
      },
  
      // Destroy this entity on the server if it was already persisted.
      // Optimistically removes the entity from its collection, if it has one.
      // If `wait: true` is passed, waits for the server to respond before removal.
      destroy: function(options) {
        options = options ? langx.clone(options) : {};
        var entity = this;
        var success = options.success;
        var wait = options.wait;
  
        var destroy = function() {
          entity.stopListening();
          entity.trigger('destroy', entity, entity.collection, options);
        };
  
        options.success = function(resp) {
          if (wait) destroy();
          if (success) success.call(options.context, entity, resp, options);
          if (!entity.isNew()) entity.trigger('sync', entity, resp, options);
        };
  
        var xhr = false;
        if (this.isNew()) {
          langx.defer(options.success);
        } else {
          wrapError(this, options);
          xhr = this.sync('delete', this, options);
        }
        if (!wait) destroy();
        return xhr;
      },
  
      // Default URL for the entity's representation on the server -- if you're
      // using Backbone's restful methods, override this to change the endpoint
      // that will be called.
      url: function() {
        var base =
          langx.result(this, 'urlRoot') ||
          langx.result(this.collection, 'url') ||
          urlError();
        if (this.isNew()) return base;
        var id = this.get(this.idAttribute);
        return base.replace(/[^\/]$/, '$&/') + encodeURIComponent(id);
      },
  
      // **parse** converts a response into the hash of attributes to be `set` on
      // the entity. The default implementation is just to pass the response along.
      parse: function(resp, options) {
        return resp;
      }
    });
  
    var Collection  = langx.Evented.inherit({
      "init" : function(entities, options) {
        options || (options = {});
        if (options.entity) this.entity = options.entity;
        if (options.comparator !== void 0) this.comparator = options.comparator;
        this._reset();
        if (entities) this.reset(entities, langx.mixin({silent: true}, options));
      }
    }); 
  
    // Default options for `Collection#set`.
    var setOptions = {add: true, remove: true, merge: true};
    var addOptions = {add: true, remove: false};
  
    // Splices `insert` into `array` at index `at`.
    var splice = function(array, insert, at) {
      at = Math.min(Math.max(at, 0), array.length);
      var tail = Array(array.length - at);
      var length = insert.length;
      var i;
      for (i = 0; i < tail.length; i++) tail[i] = array[i + at];
      for (i = 0; i < length; i++) array[i + at] = insert[i];
      for (i = 0; i < tail.length; i++) array[i + length + at] = tail[i];
    };
  
    // Define the Collection's inheritable methods.
    Collection.partial({
  
      // The default entity for a collection is just a **Entity**.
      // This should be overridden in most cases.
      entity: Entity,
  
      // Initialize is an empty function by default. Override it with your own
      // initialization logic.
      initialize: function(){},
  
      // The JSON representation of a Collection is an array of the
      // entities' attributes.
      toJSON: function(options) {
        return this.map(function(entity) { return entity.toJSON(options); });
      },
  
      // Proxy `models.sync` by default.
      sync: function() {
        return models.sync.apply(this, arguments);
      },
  
      // Add a entity, or list of entities to the set. `entities` may be Backbone
      // Entitys or raw JavaScript objects to be converted to Entitys, or any
      // combination of the two.
      add: function(entities, options) {
        return this.set(entities, langx.mixin({merge: false}, options, addOptions));
      },
  
      // Remove a entity, or a list of entities from the set.
      remove: function(entities, options) {
        options = langx.mixin({}, options);
        var singular = !langx.isArray(entities);
        entities = singular ? [entities] : entities.slice();
        var removed = this._removeEntitys(entities, options);
        if (!options.silent && removed.length) {
          options.changes = {added: [], merged: [], removed: removed};
          this.trigger('update', this, options);
        }
        return singular ? removed[0] : removed;
      },
  
      // Update a collection by `set`-ing a new list of entities, adding new ones,
      // removing entities that are no longer present, and merging entities that
      // already exist in the collection, as necessary. Similar to **Entity#set**,
      // the core operation for updating the data contained by the collection.
      set: function(entities, options) {
        if (entities == null) return;
  
        options = langx.mixin({}, setOptions, options);
        if (options.parse && !this._isEntity(entities)) {
          entities = this.parse(entities, options) || [];
        }
  
        var singular = !langx.isArray(entities);
        entities = singular ? [entities] : entities.slice();
  
        var at = options.at;
        if (at != null) at = +at;
        if (at > this.length) at = this.length;
        if (at < 0) at += this.length + 1;
  
        var set = [];
        var toAdd = [];
        var toMerge = [];
        var toRemove = [];
        var modelMap = {};
  
        var add = options.add;
        var merge = options.merge;
        var remove = options.remove;
  
        var sort = false;
        var sortable = this.comparator && at == null && options.sort !== false;
        var sortAttr = langx.isString(this.comparator) ? this.comparator : null;
  
        // Turn bare objects into entity references, and prevent invalid entities
        // from being added.
        var entity, i;
        for (i = 0; i < entities.length; i++) {
          entity = entities[i];
  
          // If a duplicate is found, prevent it from being added and
          // optionally merge it into the existing entity.
          var existing = this.get(entity);
          if (existing) {
            if (merge && entity !== existing) {
              var attrs = this._isEntity(entity) ? entity.attributes : entity;
              if (options.parse) attrs = existing.parse(attrs, options);
              existing.set(attrs, options);
              toMerge.push(existing);
              if (sortable && !sort) sort = existing.hasChanged(sortAttr);
            }
            if (!modelMap[existing.cid]) {
              modelMap[existing.cid] = true;
              set.push(existing);
            }
            entities[i] = existing;
  
          // If this is a new, valid entity, push it to the `toAdd` list.
          } else if (add) {
            entity = entities[i] = this._prepareEntity(entity, options);
            if (entity) {
              toAdd.push(entity);
              this._addReference(entity, options);
              modelMap[entity.cid] = true;
              set.push(entity);
            }
          }
        }
  
        // Remove stale entities.
        if (remove) {
          for (i = 0; i < this.length; i++) {
            entity = this.entities[i];
            if (!modelMap[entity.cid]) toRemove.push(entity);
          }
          if (toRemove.length) this._removeEntitys(toRemove, options);
        }
  
        // See if sorting is needed, update `length` and splice in new entities.
        var orderChanged = false;
        var replace = !sortable && add && remove;
        if (set.length && replace) {
          orderChanged = this.length !== set.length || this.entities.some(function(m, index) {
            return m !== set[index];
          });
          this.entities.length = 0;
          splice(this.entities, set, 0);
          this.length = this.entities.length;
        } else if (toAdd.length) {
          if (sortable) sort = true;
          splice(this.entities, toAdd, at == null ? this.length : at);
          this.length = this.entities.length;
        }
  
        // Silently sort the collection if appropriate.
        if (sort) this.sort({silent: true});
  
        // Unless silenced, it's time to fire all appropriate add/sort/update events.
        if (!options.silent) {
          for (i = 0; i < toAdd.length; i++) {
            if (at != null) options.index = at + i;
            entity = toAdd[i];
            entity.trigger('add', entity, this, options);
          }
          if (sort || orderChanged) this.trigger('sort', this, options);
          if (toAdd.length || toRemove.length || toMerge.length) {
            options.changes = {
              added: toAdd,
              removed: toRemove,
              merged: toMerge
            };
            this.trigger('update', this, options);
          }
        }
  
        // Return the added (or merged) entity (or entities).
        return singular ? entities[0] : entities;
      },
  
      // When you have more items than you want to add or remove individually,
      // you can reset the entire set with a new list of entities, without firing
      // any granular `add` or `remove` events. Fires `reset` when finished.
      // Useful for bulk operations and optimizations.
      reset: function(entities, options) {
        options = options ? langx.clone(options) : {};
        for (var i = 0; i < this.entities.length; i++) {
          this._removeReference(this.entities[i], options);
        }
        options.previousEntitys = this.entities;
        this._reset();
        entities = this.add(entities, langx.mixin({silent: true}, options));
        if (!options.silent) this.trigger('reset', this, options);
        return entities;
      },
  
      // Add a entity to the end of the collection.
      push: function(entity, options) {
        return this.add(entity, langx.mixin({at: this.length}, options));
      },
  
      // Remove a entity from the end of the collection.
      pop: function(options) {
        var entity = this.at(this.length - 1);
        return this.remove(entity, options);
      },
  
      // Add a entity to the beginning of the collection.
      unshift: function(entity, options) {
        return this.add(entity, langx.mixin({at: 0}, options));
      },
  
      // Remove a entity from the beginning of the collection.
      shift: function(options) {
        var entity = this.at(0);
        return this.remove(entity, options);
      },
  
      // Slice out a sub-array of entities from the collection.
      slice: function() {
        return slice.apply(this.entities, arguments);
      },
  
      // Get a entity from the set by id, cid, entity object with id or cid
      // properties, or an attributes object that is transformed through entityId.
      get: function(obj) {
        if (obj == null) return void 0;
        return this._byId[obj] ||
          this._byId[this.entityId(obj.attributes || obj)] ||
          obj.cid && this._byId[obj.cid];
      },
  
      // Returns `true` if the entity is in the collection.
      has: function(obj) {
        return this.get(obj) != null;
      },
  
      // Get the entity at the given index.
      at: function(index) {
        if (index < 0) index += this.length;
        return this.entities[index];
      },
  
      // Return entities with matching attributes. Useful for simple cases of
      // `filter`.
      where: function(attrs, first) {
        return this[first ? 'find' : 'filter'](attrs);
      },
  
      // Return the first entity with matching attributes. Useful for simple cases
      // of `find`.
      findWhere: function(attrs) {
        return this.where(attrs, true);
      },
  
      // Force the collection to re-sort itself. You don't need to call this under
      // normal circumstances, as the set will maintain sort order as each item
      // is added.
      sort: function(options) {
        var comparator = this.comparator;
        if (!comparator) throw new Error('Cannot sort a set without a comparator');
        options || (options = {});
  
        var length = comparator.length;
        if (langx.isFunction(comparator)) comparator = langx.proxy(comparator, this);
  
        // Run sort based on type of `comparator`.
        if (length === 1 || langx.isString(comparator)) {
          this.entities = this.sortBy(comparator);
        } else {
          this.entities.sort(comparator);
        }
        if (!options.silent) this.trigger('sort', this, options);
        return this;
      },
  
      // Pluck an attribute from each entity in the collection.
      pluck: function(attr) {
        return this.map(attr + '');
      },
  
      // Fetch the default set of entities for this collection, resetting the
      // collection when they arrive. If `reset: true` is passed, the response
      // data will be passed through the `reset` method instead of `set`.
      fetch: function(options) {
        options = langx.mixin({parse: true}, options);
        var success = options.success;
        var collection = this;
        options.success = function(resp) {
          var method = options.reset ? 'reset' : 'set';
          collection[method](resp, options);
          if (success) success.call(options.context, collection, resp, options);
          collection.trigger('sync', collection, resp, options);
        };
        wrapError(this, options);
        return this.sync('read', this, options);
      },
  
      // Create a new instance of a entity in this collection. Add the entity to the
      // collection immediately, unless `wait: true` is passed, in which case we
      // wait for the server to agree.
      create: function(entity, options) {
        options = options ? langx.clone(options) : {};
        var wait = options.wait;
        entity = this._prepareEntity(entity, options);
        if (!entity) return false;
        if (!wait) this.add(entity, options);
        var collection = this;
        var success = options.success;
        options.success = function(m, resp, callbackOpts) {
          if (wait) collection.add(m, callbackOpts);
          if (success) success.call(callbackOpts.context, m, resp, callbackOpts);
        };
        entity.save(null, options);
        return entity;
      },
  
      // **parse** converts a response into a list of entities to be added to the
      // collection. The default implementation is just to pass it through.
      parse: function(resp, options) {
        return resp;
      },
  
      // Create a new collection with an identical list of entities as this one.
      clone: function() {
        return new this.constructor(this.entities, {
          entity: this.entity,
          comparator: this.comparator
        });
      },
  
      // Define how to uniquely identify entities in the collection.
      entityId: function(attrs) {
        return attrs[this.entity.prototype.idAttribute || 'id'];
      },
  
      // Private method to reset all internal state. Called when the collection
      // is first initialized or reset.
      _reset: function() {
        this.length = 0;
        this.entities = [];
        this._byId  = {};
      },
  
      // Prepare a hash of attributes (or other entity) to be added to this
      // collection.
      _prepareEntity: function(attrs, options) {
        if (this._isEntity(attrs)) {
          if (!attrs.collection) attrs.collection = this;
          return attrs;
        }
        options = options ? langx.clone(options) : {};
        options.collection = this;
        var entity = new this.entity(attrs, options);
        if (!entity.validationError) return entity;
        this.trigger('invalid', this, entity.validationError, options);
        return false;
      },
  
      // Internal method called by both remove and set.
      _removeEntitys: function(entities, options) {
        var removed = [];
        for (var i = 0; i < entities.length; i++) {
          var entity = this.get(entities[i]);
          if (!entity) continue;
  
          var index = this.indexOf(entity);
          this.entities.splice(index, 1);
          this.length--;
  
          // Remove references before triggering 'remove' event to prevent an
          // infinite loop. #3693
          delete this._byId[entity.cid];
          var id = this.entityId(entity.attributes);
          if (id != null) delete this._byId[id];
  
          if (!options.silent) {
            options.index = index;
            entity.trigger('remove', entity, this, options);
          }
  
          removed.push(entity);
          this._removeReference(entity, options);
        }
        return removed;
      },
  
      // Method for checking whether an object should be considered a entity for
      // the purposes of adding to the collection.
      _isEntity: function(entity) {
        return entity instanceof Entity;
      },
  
      // Internal method to create a entity's ties to a collection.
      _addReference: function(entity, options) {
        this._byId[entity.cid] = entity;
        var id = this.entityId(entity.attributes);
        if (id != null) this._byId[id] = entity;
        entity.on('all', this._onEntityEvent, this);
      },
  
      // Internal method to sever a entity's ties to a collection.
      _removeReference: function(entity, options) {
        delete this._byId[entity.cid];
        var id = this.entityId(entity.attributes);
        if (id != null) delete this._byId[id];
        if (this === entity.collection) delete entity.collection;
        entity.off('all', this._onEntityEvent, this);
      },
  
      // Internal method called every time a entity in the set fires an event.
      // Sets need to update their indexes when entities change ids. All other
      // events simply proxy through. "add" and "remove" events that originate
      // in other collections are ignored.
      _onEntityEvent: function(event, entity, collection, options) {
        if (entity) {
          if ((event === 'add' || event === 'remove') && collection !== this) return;
          if (event === 'destroy') this.remove(entity, options);
          if (event === 'change') {
            var prevId = this.entityId(entity.previousAttributes());
            var id = this.entityId(entity.attributes);
            if (prevId !== id) {
              if (prevId != null) delete this._byId[prevId];
              if (id != null) this._byId[id] = entity;
            }
          }
        }
        this.trigger.apply(this, arguments);
      }
  
    });
  
      function models() {
          return models;
      }
  
      langx.mixin(models, {
          // set a `X-Http-Method-Override` header.
          emulateHTTP : false,
  
          // Turn on `emulateJSON` to support legacy servers that can't deal with direct
          // `application/json` requests ... this will encode the body as
          // `application/x-www-form-urlencoded` instead and will send the model in a
          // form param named `model`.
          emulateJSON : false,
  
          sync : sync,
  
          Entity: Entity,
          Collection : Collection
      });
  
  
      return skylark.models = models;
  });
  
  define('skylarkjs/models',[
      "skylark-utils/models"
  ], function(models) {
      return models;
  });
  
  define('skylarkjs/noder',[
      "skylark-utils/noder"
  ], function(noder) {
      return noder;
  });
  
  define('skylarkjs/query',[
      "skylark-utils/query"
  ], function(query) {
      return query;
  });
  
  define('skylark-utils/scripter',[
      "./skylark",
      "./langx",
      "./noder",
      "./finder"
  ], function(skylark, langx, noder, finder) {
  
      var head = document.getElementsByTagName('head')[0],
          scriptsByUrl = {},
          scriptElementsById = {},
          count = 0;
  
      function scripter() {
          return scripter;
      }
  
      langx.mixin(scripter, {
          /*
           * Load a script from a url into the document.
           * @param {} url
           * @param {} loadedCallback
           * @param {} errorCallback
           */
          loadJavaScript: function(url, loadedCallback, errorCallback) {
              var script = scriptsByUrl[url];
              if (!script) {
                  script = scriptsByUrl[url] = {
                      state: 0, //0:unload,1:loaded,-1:loaderror
                      loadedCallbacks: [],
                      errorCallbacks: []
                  }
              }
  
              script.loadedCallbacks.push(loadedCallback);
              script.errorCallbacks.push(errorCallback);
  
              if (script.state === 1) {
                  script.node.onload();
              } else if (script.state === -1) {
                  script.node.onerror();
              } else {
                  var node = script.node = document.createElement("script"),
                      id = script.id = (count++);
  
                  node.type = "text/javascript";
                  node.async = false;
                  node.defer = false;
                  startTime = new Date().getTime();
                  head.appendChild(node);
  
                  node.onload = function() {
                          script.state = 1;
  
                          var callbacks = script.loadedCallbacks,
                              i = callbacks.length;
  
                          while (i--) {
                              callbacks[i]();
                          }
                          script.loadedCallbacks = [];
                          script.errorCallbacks = [];
                      },
                      node.onerror = function() {
                          script.state = -1;
                          var callbacks = script.errorCallbacks,
                              i = callbacks.length;
  
                          while (i--) {
                              callbacks[i]();
                          }
                          script.loadedCallbacks = [];
                          script.errorCallbacks = [];
                      };
                  node.src = url;
  
                  scriptElementsById[id] = node;
              }
              return script.id;
          },
          /*
           * Remove the specified script from the document.
           * @param {Number} id
           */
          deleteJavaScript: function(id) {
              var node = scriptElementsById[id];
              if (node) {
                  var url = node.src;
                  noder.remove(node);
                  delete scriptElementsById[id];
                  delete scriptsByUrl[url];
              }
          }
      });
  
      return skylark.scripter = scripter;
  });
  define('skylarkjs/scripter',[
      "skylark-utils/scripter"
  ], function(scripter) {
      return scripter;
  });
  
  define('skylarkjs/styler',[
      "skylark-utils/styler"
  ], function(styler) {
      return styler;
  });
  
  define('skylark-utils/velm',[
      "./skylark",
      "./langx",
      "./datax",
      "./dnd",
      "./eventer",
      "./filer",
      "./finder",
      "./fx",
      "./geom",
      "./noder",
      "./styler"
  ], function(skylark, langx, datax, dnd, eventer, filer, finder, fx, geom, noder, styler) {
      var map = Array.prototype.map,
          slice = Array.prototype.slice;
      /*
       * VisualElement is a skylark class type wrapping a visule dom node,provides a number of prototype methods and supports chain calls.
       */
      var VisualElement = langx.klass({
          klassName: "VisualElement",
  
          "init": function(node) {
              if (langx.isString(node)) {
                  node = document.getElementById(node);
              }
              this.domNode = node;
          }
      });
      /*
       * the VisualElement object wrapping document.body
       */
      var root = new VisualElement(document.body),
          velm = function(node) {
              if (node) {
                  return new VisualElement(node);
              } else {
                  return root;
              }
          };
      /*
       * Extend VisualElement prototype with wrapping the specified methods.
       * @param {ArrayLike} fn
       * @param {Object} context
       */
      function _delegator(fn, context) {
          return function() {
              var self = this,
                  elem = self.domNode,
                  ret = fn.apply(context, [elem].concat(slice.call(arguments)));
  
              if (ret) {
                  if (ret === context) {
                      return self;
                  } else {
                      if (ret instanceof HTMLElement) {
                          ret = new VisualElement(ret);
                      } else if (langx.isArrayLike(ret)) {
                          ret = map.call(ret, function(el) {
                              if (el instanceof HTMLElement) {
                                  return new VisualElement(ret);
                              } else {
                                  return el;
                              }
                          })
                      }
                  }
              }
              return ret;
          };
      }
  
      langx.mixin(velm, {
          batch: function(nodes, action, args) {
              nodes.forEach(function(node) {
                  var elm = (node instanceof VisualElement) ? node : velm(node);
                  elm[action].apply(elm, args);
              });
  
              return this;
          },
  
          root: new VisualElement(document.body),
  
          VisualElement: VisualElement,
  
          partial: function(name, fn) {
              var props = {};
  
              props[name] = fn;
  
              VisualElement.partial(props);
          },
  
          delegate: function(names, context) {
              var props = {};
  
              names.forEach(function(name) {
                  props[name] = _delegator(context[name], context);
              });
  
              VisualElement.partial(props);
          }
      });
  
      // from ./datax
      velm.delegate([
          "attr",
          "data",
          "prop",
          "removeAttr",
          "removeData",
          "text",
          "val"
      ], datax);
  
      // from ./dnd
      velm.delegate([
          "draggable",
          "droppable"
      ], dnd);
  
  
      // from ./eventer
      velm.delegate([
          "off",
          "on",
          "one",
          "shortcuts",
          "trigger"
      ], eventer);
  
      // from ./filer
      velm.delegate([
          "picker",
          "dropzone"
      ], filer);
  
      // from ./finder
      velm.delegate([
          "ancestor",
          "ancestors",
          "children",
          "descendant",
          "find",
          "findAll",
          "firstChild",
          "lastChild",
          "matches",
          "nextSibling",
          "nextSiblings",
          "parent",
          "previousSibling",
          "previousSiblings",
          "siblings"
      ], finder);
  
      /*
       * find a dom element matched by the specified selector.
       * @param {String} selector
       */
      velm.find = function(selector) {
          if (selector === "body") {
              return this.root;
          } else {
              return this.root.descendant(selector);
          }
      };
  
      // from ./fx
      velm.delegate([
          "animate",
          "fadeIn",
          "fadeOut",
          "fadeTo",
          "fadeToggle",
          "hide",
          "scrollToTop",
          "show",
          "toggle"
      ], fx);
  
  
      // from ./geom
      velm.delegate([
          "borderExtents",
          "boundingPosition",
          "boundingRect",
          "clientHeight",
          "clientSize",
          "clientWidth",
          "contentRect",
          "height",
          "marginExtents",
          "offsetParent",
          "paddingExtents",
          "pagePosition",
          "pageRect",
          "relativePosition",
          "relativeRect",
          "scrollIntoView",
          "scrollLeft",
          "scrollTop",
          "size",
          "width"
      ], geom);
  
      // from ./mover
      velm.delegate([
          "draggable",
          "droppable"
      ], dnd);
  
  
      // from ./noder
      velm.delegate([
          "after",
          "append",
          "before",
          "clone",
          "contains",
          "contents",
          "empty",
          "html",
          "isChildOf",
          "ownerDoc",
          "prepend",
          "remove",
          "removeChild",
          "replace",
          "reverse",
          "throb",
          "traverse",
          "wrapper",
          "wrapperInner",
          "unwrap"
      ], noder);
  
      // from ./styler
      velm.delegate([
          "addClass",
          "className",
          "css",
          "hasClass",
          "hide",
          "isInvisible",
          "removeClass",
          "show",
          "toggleClass"
      ], styler);
  
      // properties
  
      var properties = [ 'position', 'left', 'top', 'right', 'bottom', 'width', 'height', 'border', 'borderLeft',
      'borderTop', 'borderRight', 'borderBottom', 'borderColor', 'display', 'overflow', 'margin', 'marginLeft', 'marginTop', 'marginRight', 'marginBottom', 'padding', 'paddingLeft', 'paddingTop', 'paddingRight', 'paddingBottom', 'color',
      'background', 'backgroundColor', 'opacity', 'fontSize', 'fontWeight', 'textAlign', 'textDecoration', 'textTransform', 'cursor', 'zIndex' ];
  
      properties.forEach( function ( property ) {
  
          var method = property;
  
          VisualElement.prototype[method ] = function (value) {
  
              this.css( property, value );
  
              return this;
  
          };
  
      });
  
      // events
      var events = [ 'keyUp', 'keyDown', 'mouseOver', 'mouseOut', 'click', 'dblClick', 'change' ];
  
      events.forEach( function ( event ) {
  
          var method = event;
  
          VisualElement.prototype[method ] = function ( callback ) {
  
              this.on( event.toLowerCase(), callback);
  
              return this;
          };
  
      });
  
      return skylark.velm = velm;
  });
  define('skylarkjs/velm',[
      "skylark-utils/velm"
  ], function(velm) {
      return velm;
  });
  
  define('skylark-utils/widgets',[
      "./skylark",
      "./langx",
      "./noder",
      "./datax",
      "./styler",
      "./geom",
      "./eventer",
      "./query",
      "./velm"
  ], function(skylark,langx,noder, datax, styler, geom, eventer,query,velm) {
  	// Cached regex to split keys for `delegate`.
  	var delegateEventSplitter = /^(\S+)\s*(.*)$/,
  		slice = Array.prototype.slice;
  
  
  	function bridge( name, object ) {
  		var fullName = object.prototype.widgetFullName || name,
  			fn = {};
  
  		function _delegate (isQuery) {
  
  		}
  
  		fn[name] = function( options ) {
  			var isMethodCall = typeof options === "string";
  			var args = slice.call( arguments, 1 );
  			var returnValue = this;
  
  			if ( isMethodCall ) {
  
  				// If this is an empty collection, we need to have the instance method
  				// return undefined instead of the jQuery instance
  				if ( !this.length && options === "instance" ) {
  					returnValue = undefined;
  				} else {
  					this.each( function() {
  						var methodValue;
  						var instance = datax.data( this, fullName );
  
  						if ( options === "instance" ) {
  							returnValue = instance;
  							return false;
  						}
  
  						if ( !instance ) {
  							return $.error( "cannot call methods on " + name +
  								" prior to initialization; " +
  								"attempted to call method '" + options + "'" );
  						}
  
  						if ( !langx.isFunction( instance[ options ] ) || options.charAt( 0 ) === "_" ) {
  							return $.error( "no such method '" + options + "' for " + name +
  								" widget instance" );
  						}
  
  						methodValue = instance[ options ].apply( instance, args );
  
  						if ( methodValue !== instance && methodValue !== undefined ) {
  							returnValue = methodValue && methodValue.jquery ?
  								returnValue.pushStack( methodValue.get() ) :
  								methodValue;
  							return false;
  						}
  					} );
  				}
  			} else {
  
  				// Allow multiple hashes to be passed on init
  				if ( args.length ) {
  					options = $.widget.extend.apply( null, [ options ].concat( args ) );
  				}
  
  				this.each( function() {
  					var instance = datax.data( this, fullName );
  					if ( instance ) {
  						instance.option( options || {} );
  						if ( instance._init ) {
  							instance._init();
  						}
  					} else {
  						datax.data( this, fullName, new object( options, this ) );
  					}
  				} );
  			}
  
  			return returnValue;
  		};
  	};
  
  	function widgets() {
  	    return widgets;
  	}
  
  	var Widget = langx.Evented.inherit({
  	    init :function(el,options) {
  	    	//for supporting init(options,el)
  	        if (langx.isHtmlNode(options)) {
  	        	var _t = el,
  	        		options = el;
  	            el = options;
  	        }
  	        if (langx.isHtmlNode(el)) { 
  	        	this.el = el;
  	    	} else {
  	    		this.el = null;
  	    	}
  	        if (options) {
  	            langx.mixin(this,options);
  	        }
  	        if (!this.cid) {
  	            this.cid = langx.uniqueId('w');
  	        }
  	        this._ensureElement();
  	    },
  
  	    // The default `tagName` of a View's element is `"div"`.
  	    tagName: 'div',
  
  	    // query delegate for element lookup, scoped to DOM elements within the
  	    // current view. This should be preferred to global lookups where possible.
  	    $: function(selector) {
  	      return this.$el.find(selector);
  	    },
  
  	    // **render** is the core function that your view should override, in order
  	    // to populate its element (`this.el`), with the appropriate HTML. The
  	    // convention is for **render** to always return `this`.
  	    render: function() {
  	      return this;
  	    },
  
  	    // Remove this view by taking the element out of the DOM, and removing any
  	    // applicable Backbone.Events listeners.
  	    remove: function() {
  	      this._removeElement();
  	      this.unlistenTo();
  	      return this;
  	    },
  
  	    // Remove this view's element from the document and all event listeners
  	    // attached to it. Exposed for subclasses using an alternative DOM
  	    // manipulation API.
  	    _removeElement: function() {
  	      this.$el.remove();
  	    },
  
  	    // Change the view's element (`this.el` property) and re-delegate the
  	    // view's events on the new element.
  	    setElement: function(element) {
  	      this.undelegateEvents();
  	      this._setElement(element);
  	      this.delegateEvents();
  	      return this;
  	    },
  
  	    // Creates the `this.el` and `this.$el` references for this view using the
  	    // given `el`. `el` can be a CSS selector or an HTML string, a jQuery
  	    // context or an element. Subclasses can override this to utilize an
  	    // alternative DOM manipulation API and are only required to set the
  	    // `this.el` property.
  	    _setElement: function(el) {
  	      this.$el = widgets.$(el);
  	      this.el = this.$el[0];
  	    },
  
  	    // Set callbacks, where `this.events` is a hash of
  	    //
  	    // *{"event selector": "callback"}*
  	    //
  	    //     {
  	    //       'mousedown .title':  'edit',
  	    //       'click .button':     'save',
  	    //       'click .open':       function(e) { ... }
  	    //     }
  	    //
  	    // pairs. Callbacks will be bound to the view, with `this` set properly.
  	    // Uses event delegation for efficiency.
  	    // Omitting the selector binds the event to `this.el`.
  	    delegateEvents: function(events) {
  	      events || (events = langx.result(this, 'events'));
  	      if (!events) return this;
  	      this.undelegateEvents();
  	      for (var key in events) {
  	        var method = events[key];
  	        if (!langx.isFunction(method)) method = this[method];
  	        if (!method) continue;
  	        var match = key.match(delegateEventSplitter);
  	        this.delegate(match[1], match[2], langx.proxy(method, this));
  	      }
  	      return this;
  	    },
  
  	    // Add a single event listener to the view's element (or a child element
  	    // using `selector`). This only works for delegate-able events: not `focus`,
  	    // `blur`, and not `change`, `submit`, and `reset` in Internet Explorer.
  	    delegate: function(eventName, selector, listener) {
  	      this.$el.on(eventName + '.delegateEvents' + this.uid, selector, listener);
  	      return this;
  	    },
  
  	    // Clears all callbacks previously bound to the view by `delegateEvents`.
  	    // You usually don't need to use this, but may wish to if you have multiple
  	    // Backbone views attached to the same DOM element.
  	    undelegateEvents: function() {
  	      if (this.$el) this.$el.off('.delegateEvents' + this.uid);
  	      return this;
  	    },
  
  	    // A finer-grained `undelegateEvents` for removing a single delegated event.
  	    // `selector` and `listener` are both optional.
  	    undelegate: function(eventName, selector, listener) {
  	      this.$el.off(eventName + '.delegateEvents' + this.uid, selector, listener);
  	      return this;
  	    },
  
  	    // Produces a DOM element to be assigned to your view. Exposed for
  	    // subclasses using an alternative DOM manipulation API.
  	    _createElement: function(tagName,attrs) {
  	      return noder.createElement(tagName,attrs);
  	    },
  
  	    // Ensure that the View has a DOM element to render into.
  	    // If `this.el` is a string, pass it through `$()`, take the first
  	    // matching element, and re-assign it to `el`. Otherwise, create
  	    // an element from the `id`, `className` and `tagName` properties.
  	    _ensureElement: function() {
  	      if (!this.el) {
  	        var attrs = langx.mixin({}, langx.result(this, 'attributes'));
  	        if (this.id) attrs.id = langx.result(this, 'id');
  	        if (this.className) attrs['class'] = langx.result(this, 'className');
  	        this.setElement(this._createElement(langx.result(this, 'tagName'),attrs));
  	        this._setAttributes(attrs);
  	      } else {
  	        this.setElement(langx.result(this, 'el'));
  	      }
  	    },
  
  	    // Set attributes from a hash on this view's element.  Exposed for
  	    // subclasses using an alternative DOM manipulation API.
  	    _setAttributes: function(attributes) {
  	      this.$el.attr(attributes);
  	    },
  
  	    // Translation function, gets the message key to be translated
  	    // and an object with context specific data as arguments:
  	    i18n: function (message, context) {
  	        message = (this.messages && this.messages[message]) || message.toString();
  	        if (context) {
  	            langx.each(context, function (key, value) {
  	                message = message.replace('{' + key + '}', value);
  	            });
  	        }
  	        return message;
  	    },
  
  		});
  
  	function defineWidgetClass(name,base,prototype) {
  
  	};
  
  	langx.mixin(widgets, {
  		$ : query,
  
  		define : defineWidgetClass,
  		Widget : Widget
  	});
  
  
  	return skylark.widgets = widgets;
  });
  
  define('skylarkjs/widgets',[
      "skylark-utils/widgets"
  ], function(widgets) {
      return widgets;
  });
  
  define('skylarkjs/main',[
      "./core",
      "./browser",
      "./css",
      "./datax",
      "./dnd",
      "./eventer",
      "./filer",
      "./finder",
      "./fx",
      "./geom",
      "./images",
      "./langx",
      "./models",
      "./noder",
      "./query",
      "./scripter",
      "./styler",
      "./velm",
      "./widgets"
  ], function(skylark) {
      return skylark;
  })
  ;
  define('skylarkjs', ['skylarkjs/main'], function (main) { return main; });
  
  
  },this);