text: // Copyright (c) 2009, Baidu Inc. All rights reserved.
  //
  // Licensed under the BSD License
  // you may not use this file except in compliance with the License.
  // You may obtain a copy of the License at
  //
  //      http:// tangram.baidu.com/license.html
  //
  // Unless required by applicable law or agreed to in writing, software
  // distributed under the License is distributed on an "AS-IS" BASIS,
  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  // See the License for the specific language governing permissions and
  // limitations under the License.
  /**
  * @namespace T Tangram七巧板
  * @name T
  * @version 1.6.0
  */
  
  /**
   * 声明baidu包
   * @author: allstar, erik, meizz, berg
   */
  var T,
      baidu = T = baidu || { version: "1.5.0" };
  baidu.guid = "$BAIDU$";
  baidu.$$ = window[baidu.guid] = window[baidu.guid] || { global: {} };
  
  /**
   * 使用flash资源封装的一些功能
   * @namespace baidu.flash
   */
  baidu.flash = baidu.flash || {};
  
  /**
   * 操作dom的方法
   * @namespace baidu.dom
   */
  baidu.dom = baidu.dom || {};
  
  /**
   * 从文档中获取指定的DOM元素
   * @name baidu.dom.g
   * @function
   * @grammar baidu.dom.g(id)
   * @param {string|HTMLElement} id 元素的id或DOM元素.
   * @shortcut g,T.G
   * @meta standard
   * @see baidu.dom.q
   *
   * @return {HTMLElement|null} 获取的元素，查找不到时返回null,如果参数不合法，直接返回参数.
   */
  baidu.dom.g = function (id) {
      if (!id) return null;
      if ('string' == typeof id || id instanceof String) {
          return document.getElementById(id);
      } else if (id.nodeName && (id.nodeType == 1 || id.nodeType == 9)) {
          return id;
      }
      return null;
  };
  baidu.g = baidu.G = baidu.dom.g;
  
  /**
   * 操作数组的方法
   * @namespace baidu.array
   */
  
  baidu.array = baidu.array || {};
  
  /**
   * 遍历数组中所有元素
   * @name baidu.array.each
   * @function
   * @grammar baidu.array.each(source, iterator[, thisObject])
   * @param {Array} source 需要遍历的数组
   * @param {Function} iterator 对每个数组元素进行调用的函数，该函数有两个参数，第一个为数组元素，第二个为数组索引值，function (item, index)。
   * @param {Object} [thisObject] 函数调用时的this指针，如果没有此参数，默认是当前遍历的数组
   * @remark
   * each方法不支持对Object的遍历,对Object的遍历使用baidu.object.each 。
   * @shortcut each
   * @meta standard
   *
   * @returns {Array} 遍历的数组
   */
  
  baidu.each = baidu.array.forEach = baidu.array.each = function (source, iterator, thisObject) {
      var returnValue, item, i, len = source.length;
  
      if ('function' == typeof iterator) {
          for (i = 0; i < len; i++) {
              item = source[i];
              returnValue = iterator.call(thisObject || source, item, i);
  
              if (returnValue === false) {
                  break;
              }
          }
      }
      return source;
  };
  
  /**
   * 对语言层面的封装，包括类型判断、模块扩展、继承基类以及对象自定义事件的支持。
   * @namespace baidu.lang
   */
  baidu.lang = baidu.lang || {};
  
  /**
   * 判断目标参数是否为function或Function实例
   * @name baidu.lang.isFunction
   * @function
   * @grammar baidu.lang.isFunction(source)
   * @param {Any} source 目标参数
   * @version 1.2
   * @see baidu.lang.isString,baidu.lang.isObject,baidu.lang.isNumber,baidu.lang.isArray,baidu.lang.isElement,baidu.lang.isBoolean,baidu.lang.isDate
   * @meta standard
   * @returns {boolean} 类型判断结果
   */
  baidu.lang.isFunction = function (source) {
      return '[object Function]' == Object.prototype.toString.call(source);
  };
  
  /**
   * 判断目标参数是否string类型或String对象
   * @name baidu.lang.isString
   * @function
   * @grammar baidu.lang.isString(source)
   * @param {Any} source 目标参数
   * @shortcut isString
   * @meta standard
   * @see baidu.lang.isObject,baidu.lang.isNumber,baidu.lang.isArray,baidu.lang.isElement,baidu.lang.isBoolean,baidu.lang.isDate
   *
   * @returns {boolean} 类型判断结果
   */
  baidu.lang.isString = function (source) {
      return '[object String]' == Object.prototype.toString.call(source);
  };
  baidu.isString = baidu.lang.isString;
  
  /**
   * 判断浏览器类型和特性的属性
   * @namespace baidu.browser
   */
  baidu.browser = baidu.browser || {};
  
  /**
   * 判断是否为opera浏览器
   * @property opera opera版本号
   * @grammar baidu.browser.opera
   * @meta standard
   * @see baidu.browser.ie,baidu.browser.firefox,baidu.browser.safari,baidu.browser.chrome
   * @returns {Number} opera版本号
   */
  
  /**
   * opera 从10开始不是用opera后面的字符串进行版本的判断
   * 在Browser identification最后添加Version + 数字进行版本标识
   * opera后面的数字保持在9.80不变
   */
  baidu.browser.opera = /opera(\/| )(\d+(\.\d+)?)(.+?(version\/(\d+(\.\d+)?)))?/i.test(navigator.userAgent) ? + (RegExp["\x246"] || RegExp["\x242"]) : undefined;
  
  /**
   * 在目标元素的指定位置插入HTML代码
   * @name baidu.dom.insertHTML
   * @function
   * @grammar baidu.dom.insertHTML(element, position, html)
   * @param {HTMLElement|string} element 目标元素或目标元素的id
   * @param {string} position 插入html的位置信息，取值为beforeBegin,afterBegin,beforeEnd,afterEnd
   * @param {string} html 要插入的html
   * @remark
   *
   * 对于position参数，大小写不敏感<br>
   * 参数的意思：beforeBegin&lt;span&gt;afterBegin   this is span! beforeEnd&lt;/span&gt; afterEnd <br />
   * 此外，如果使用本函数插入带有script标签的HTML字符串，script标签对应的脚本将不会被执行。
   *
   * @shortcut insertHTML
   * @meta standard
   *
   * @returns {HTMLElement} 目标元素
   */
  baidu.dom.insertHTML = function (element, position, html) {
      element = baidu.dom.g(element);
      var range, begin;
      if (element.insertAdjacentHTML && !baidu.browser.opera) {
          element.insertAdjacentHTML(position, html);
      } else {
          range = element.ownerDocument.createRange();
          position = position.toUpperCase();
          if (position == 'AFTERBEGIN' || position == 'BEFOREEND') {
              range.selectNodeContents(element);
              range.collapse(position == 'AFTERBEGIN');
          } else {
              begin = position == 'BEFOREBEGIN';
              range[begin ? 'setStartBefore' : 'setEndAfter'](element);
              range.collapse(begin);
          }
          range.insertNode(range.createContextualFragment(html));
      }
      return element;
  };
  
  baidu.insertHTML = baidu.dom.insertHTML;
  
  /**
   * 操作flash对象的方法，包括创建flash对象、获取flash对象以及判断flash插件的版本号
   * @namespace baidu.swf
   */
  baidu.swf = baidu.swf || {};
  
  /**
   * 浏览器支持的flash插件版本
   * @property version 浏览器支持的flash插件版本
   * @grammar baidu.swf.version
   * @return {String} 版本号
   * @meta standard
   */
  baidu.swf.version = (function () {
      var n = navigator;
      if (n.plugins && n.mimeTypes.length) {
          var plugin = n.plugins["Shockwave Flash"];
          if (plugin && plugin.description) {
              return plugin.description
                  .replace(/([a-zA-Z]|\s)+/, "")
                  .replace(/(\s)+r/, ".") + ".0";
          }
      } else if (window.ActiveXObject && !window.opera) {
          for (var i = 12; i >= 2; i--) {
              try {
                  var c = new ActiveXObject('ShockwaveFlash.ShockwaveFlash.' + i);
                  if (c) {
                      var version = c.GetVariable("$version");
                      return version.replace(/WIN/g, '').replace(/,/g, '.');
                  }
              } catch (e) { }
          }
      }
  })();
  
  /**
   * 操作字符串的方法
   * @namespace baidu.string
   */
  baidu.string = baidu.string || {};
  
  /**
   * 对目标字符串进行html编码
   * @name baidu.string.encodeHTML
   * @function
   * @grammar baidu.string.encodeHTML(source)
   * @param {string} source 目标字符串
   * @remark
   * 编码字符有5个：&<>"'
   * @shortcut encodeHTML
   * @meta standard
   * @see baidu.string.decodeHTML
   *
   * @returns {string} html编码后的字符串
   */
  baidu.string.encodeHTML = function (source) {
      return String(source)
          .replace(/&/g, '&amp;')
          .replace(/</g, '&lt;')
          .replace(/>/g, '&gt;')
          .replace(/"/g, "&quot;")
          .replace(/'/g, "&#39;");
  };
  
  baidu.encodeHTML = baidu.string.encodeHTML;
  
  /**
   * 创建flash对象的html字符串
   * @name baidu.swf.createHTML
   * @function
   * @grammar baidu.swf.createHTML(options)
   *
   * @param {Object} 	options 					创建flash的选项参数
   * @param {string} 	options.id 					要创建的flash的标识
   * @param {string} 	options.url 				flash文件的url
   * @param {String} 	options.errorMessage 		未安装flash player或flash player版本号过低时的提示
   * @param {string} 	options.ver 				最低需要的flash player版本号
   * @param {string} 	options.width 				flash的宽度
   * @param {string} 	options.height 				flash的高度
   * @param {string} 	options.align 				flash的对齐方式，允许值：middle/left/right/top/bottom
   * @param {string} 	options.base 				设置用于解析swf文件中的所有相对路径语句的基本目录或URL
   * @param {string} 	options.bgcolor 			swf文件的背景色
   * @param {string} 	options.salign 				设置缩放的swf文件在由width和height设置定义的区域内的位置。允许值：l/r/t/b/tl/tr/bl/br
   * @param {boolean} options.menu 				是否显示右键菜单，允许值：true/false
   * @param {boolean} options.loop 				播放到最后一帧时是否重新播放，允许值： true/false
   * @param {boolean} options.play 				flash是否在浏览器加载时就开始播放。允许值：true/false
   * @param {string} 	options.quality 			设置flash播放的画质，允许值：low/medium/high/autolow/autohigh/best
   * @param {string} 	options.scale 				设置flash内容如何缩放来适应设置的宽高。允许值：showall/noborder/exactfit
   * @param {string} 	options.wmode 				设置flash的显示模式。允许值：window/opaque/transparent
   * @param {string} 	options.allowscriptaccess 	设置flash与页面的通信权限。允许值：always/never/sameDomain
   * @param {string} 	options.allownetworking 	设置swf文件中允许使用的网络API。允许值：all/internal/none
   * @param {boolean} options.allowfullscreen 	是否允许flash全屏。允许值：true/false
   * @param {boolean} options.seamlesstabbing 	允许设置执行无缝跳格，从而使用户能跳出flash应用程序。该参数只能在安装Flash7及更高版本的Windows中使用。允许值：true/false
   * @param {boolean} options.devicefont 			设置静态文本对象是否以设备字体呈现。允许值：true/false
   * @param {boolean} options.swliveconnect 		第一次加载flash时浏览器是否应启动Java。允许值：true/false
   * @param {Object} 	options.vars 				要传递给flash的参数，支持JSON或string类型。
   *
   * @see baidu.swf.create
   * @meta standard
   * @returns {string} flash对象的html字符串
   */
  baidu.swf.createHTML = function (options) {
      options = options || {};
      var version = baidu.swf.version,
          needVersion = options['ver'] || '6.0.0',
          vUnit1, vUnit2, i, k, len, item, tmpOpt = {},
          encodeHTML = baidu.string.encodeHTML;
      for (k in options) {
          tmpOpt[k] = options[k];
      }
      options = tmpOpt;
      if (version) {
          version = version.split('.');
          needVersion = needVersion.split('.');
          for (i = 0; i < 3; i++) {
              vUnit1 = parseInt(version[i], 10);
              vUnit2 = parseInt(needVersion[i], 10);
              if (vUnit2 < vUnit1) {
                  break;
              } else if (vUnit2 > vUnit1) {
                  return '';
              }
          }
      } else {
          return '';
      }
  
      var vars = options['vars'],
          objProperties = ['classid', 'codebase', 'id', 'width', 'height', 'align'];
      options['align'] = options['align'] || 'middle';
      options['classid'] = 'clsid:d27cdb6e-ae6d-11cf-96b8-444553540000';
      options['codebase'] = 'http://fpdownload.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,0,0';
      options['movie'] = options['url'] || '';
      delete options['vars'];
      delete options['url'];
      if ('string' == typeof vars) {
          options['flashvars'] = vars;
      } else {
          var fvars = [];
          for (k in vars) {
              item = vars[k];
              fvars.push(k + "=" + encodeURIComponent(item));
          }
          options['flashvars'] = fvars.join('&');
      }
      var str = ['<object '];
      for (i = 0, len = objProperties.length; i < len; i++) {
          item = objProperties[i];
          str.push(' ', item, '="', encodeHTML(options[item]), '"');
      }
      str.push('>');
      var params = {
          'wmode': 1,
          'scale': 1,
          'quality': 1,
          'play': 1,
          'loop': 1,
          'menu': 1,
          'salign': 1,
          'bgcolor': 1,
          'base': 1,
          'allowscriptaccess': 1,
          'allownetworking': 1,
          'allowfullscreen': 1,
          'seamlesstabbing': 1,
          'devicefont': 1,
          'swliveconnect': 1,
          'flashvars': 1,
          'movie': 1
      };
  
      for (k in options) {
          item = options[k];
          k = k.toLowerCase();
          if (params[k] && (item || item === false || item === 0)) {
              str.push('<param name="' + k + '" value="' + encodeHTML(item) + '" />');
          }
      }
      options['src'] = options['movie'];
      options['name'] = options['id'];
      delete options['id'];
      delete options['movie'];
      delete options['classid'];
      delete options['codebase'];
      options['type'] = 'application/x-shockwave-flash';
      options['pluginspage'] = 'http://www.macromedia.com/go/getflashplayer';
      str.push('<embed');
      var salign;
      for (k in options) {
          item = options[k];
          if (item || item === false || item === 0) {
              if ((new RegExp("^salign\x24", "i")).test(k)) {
                  salign = item;
                  continue;
              }
  
              str.push(' ', k, '="', encodeHTML(item), '"');
          }
      }
  
      if (salign) {
          str.push(' salign="', encodeHTML(salign), '"');
      }
      str.push('></embed></object>');
  
      return str.join('');
  };
  
  /**
   * 在页面中创建一个flash对象
   * @name baidu.swf.create
   * @function
   * @grammar baidu.swf.create(options[, container])
   *
   * @param {Object} 	options 					创建flash的选项参数
   * @param {string} 	options.id 					要创建的flash的标识
   * @param {string} 	options.url 				flash文件的url
   * @param {String} 	options.errorMessage 		未安装flash player或flash player版本号过低时的提示
   * @param {string} 	options.ver 				最低需要的flash player版本号
   * @param {string} 	options.width 				flash的宽度
   * @param {string} 	options.height 				flash的高度
   * @param {string} 	options.align 				flash的对齐方式，允许值：middle/left/right/top/bottom
   * @param {string} 	options.base 				设置用于解析swf文件中的所有相对路径语句的基本目录或URL
   * @param {string} 	options.bgcolor 			swf文件的背景色
   * @param {string} 	options.salign 				设置缩放的swf文件在由width和height设置定义的区域内的位置。允许值：l/r/t/b/tl/tr/bl/br
   * @param {boolean} options.menu 				是否显示右键菜单，允许值：true/false
   * @param {boolean} options.loop 				播放到最后一帧时是否重新播放，允许值： true/false
   * @param {boolean} options.play 				flash是否在浏览器加载时就开始播放。允许值：true/false
   * @param {string} 	options.quality 			设置flash播放的画质，允许值：low/medium/high/autolow/autohigh/best
   * @param {string} 	options.scale 				设置flash内容如何缩放来适应设置的宽高。允许值：showall/noborder/exactfit
   * @param {string} 	options.wmode 				设置flash的显示模式。允许值：window/opaque/transparent
   * @param {string} 	options.allowscriptaccess 	设置flash与页面的通信权限。允许值：always/never/sameDomain
   * @param {string} 	options.allownetworking 	设置swf文件中允许使用的网络API。允许值：all/internal/none
   * @param {boolean} options.allowfullscreen 	是否允许flash全屏。允许值：true/false
   * @param {boolean} options.seamlesstabbing 	允许设置执行无缝跳格，从而使用户能跳出flash应用程序。该参数只能在安装Flash7及更高版本的Windows中使用。允许值：true/false
   * @param {boolean} options.devicefont 			设置静态文本对象是否以设备字体呈现。允许值：true/false
   * @param {boolean} options.swliveconnect 		第一次加载flash时浏览器是否应启动Java。允许值：true/false
   * @param {Object} 	options.vars 				要传递给flash的参数，支持JSON或string类型。
   *
   * @param {HTMLElement|string} [container] 		flash对象的父容器元素，不传递该参数时在当前代码位置创建flash对象。
   * @meta standard
   * @see baidu.swf.createHTML,baidu.swf.getMovie
   */
  baidu.swf.create = function (options, target) {
      options = options || {};
      var html = baidu.swf.createHTML(options)
          || options['errorMessage']
          || '';
  
      if (target && 'string' == typeof target) {
          target = document.getElementById(target);
      }
      baidu.dom.insertHTML(target || document.body, 'beforeEnd', html);
  };
  /**
   * 判断是否为ie浏览器
   * @name baidu.browser.ie
   * @field
   * @grammar baidu.browser.ie
   * @returns {Number} IE版本号
   */
  baidu.browser.ie = baidu.ie = /msie (\d+\.\d+)/i.test(navigator.userAgent) ? (document.documentMode || + RegExp['\x241']) : undefined;
  
  /**
   * 移除数组中的项
   * @name baidu.array.remove
   * @function
   * @grammar baidu.array.remove(source, match)
   * @param {Array} source 需要移除项的数组
   * @param {Any} match 要移除的项
   * @meta standard
   * @see baidu.array.removeAt
   *
   * @returns {Array} 移除后的数组
   */
  baidu.array.remove = function (source, match) {
      var len = source.length;
  
      while (len--) {
          if (len in source && source[len] === match) {
              source.splice(len, 1);
          }
      }
      return source;
  };
  
  /**
   * 判断目标参数是否Array对象
   * @name baidu.lang.isArray
   * @function
   * @grammar baidu.lang.isArray(source)
   * @param {Any} source 目标参数
   * @meta standard
   * @see baidu.lang.isString,baidu.lang.isObject,baidu.lang.isNumber,baidu.lang.isElement,baidu.lang.isBoolean,baidu.lang.isDate
   *
   * @returns {boolean} 类型判断结果
   */
  baidu.lang.isArray = function (source) {
      return '[object Array]' == Object.prototype.toString.call(source);
  };
  
  /**
   * 将一个变量转换成array
   * @name baidu.lang.toArray
   * @function
   * @grammar baidu.lang.toArray(source)
   * @param {mix} source 需要转换成array的变量
   * @version 1.3
   * @meta standard
   * @returns {array} 转换后的array
   */
  baidu.lang.toArray = function (source) {
      if (source === null || source === undefined)
          return [];
      if (baidu.lang.isArray(source))
          return source;
      if (typeof source.length !== 'number' || typeof source === 'string' || baidu.lang.isFunction(source)) {
          return [source];
      }
      if (source.item) {
          var l = source.length, array = new Array(l);
          while (l--)
              array[l] = source[l];
          return array;
      }
  
      return [].slice.call(source);
  };
  
  /**
   * 获得flash对象的实例
   * @name baidu.swf.getMovie
   * @function
   * @grammar baidu.swf.getMovie(name)
   * @param {string} name flash对象的名称
   * @see baidu.swf.create
   * @meta standard
   * @returns {HTMLElement} flash对象的实例
   */
  baidu.swf.getMovie = function (name) {
      var movie = document[name], ret;
      return baidu.browser.ie == 9 ?
          movie && movie.length ?
              (ret = baidu.array.remove(baidu.lang.toArray(movie), function (item) {
                  return item.tagName.toLowerCase() != "embed";
              })).length == 1 ? ret[0] : ret
              : movie
          : movie || window[name];
  };
  
  baidu.flash._Base = (function () {
      var prefix = 'bd__flash__';
  
      /**
       * 创建一个随机的字符串
       * @private
       * @return {String}
       */
      function _createString() {
          return prefix + Math.floor(Math.random() * 2147483648).toString(36);
      };
  
      /**
       * 检查flash状态
       * @private
       * @param {Object} target flash对象
       * @return {Boolean}
       */
      function _checkReady(target) {
          if (typeof target !== 'undefined' && typeof target.flashInit !== 'undefined' && target.flashInit()) {
              return true;
          } else {
              return false;
          }
      };
  
      /**
       * 调用之前进行压栈的函数
       * @private
       * @param {Array} callQueue 调用队列
       * @param {Object} target flash对象
       * @return {Null}
       */
      function _callFn(callQueue, target) {
          var result = null;
  
          callQueue = callQueue.reverse();
          baidu.each(callQueue, function (item) {
              result = target.call(item.fnName, item.params);
              item.callBack(result);
          });
      };
  
      /**
       * 为传入的匿名函数创建函数名
       * @private
       * @param {String|Function} fun 传入的匿名函数或者函数名
       * @return {String}
       */
      function _createFunName(fun) {
          var name = '';
  
          if (baidu.lang.isFunction(fun)) {
              name = _createString();
              window[name] = function () {
                  fun.apply(window, arguments);
              };
  
              return name;
          } else if (baidu.lang.isString) {
              return fun;
          }
      };
  
      /**
       * 绘制flash
       * @private
       * @param {Object} options 创建参数
       * @return {Object}
       */
      function _render(options) {
          if (!options.id) {
              options.id = _createString();
          }
  
          var container = options.container || '';
          delete (options.container);
  
          baidu.swf.create(options, container);
  
          return baidu.swf.getMovie(options.id);
      };
  
      return function (options, callBack) {
          var me = this,
              autoRender = (typeof options.autoRender !== 'undefined' ? options.autoRender : true),
              createOptions = options.createOptions || {},
              target = null,
              isReady = false,
              callQueue = [],
              timeHandle = null,
              callBack = callBack || [];
  
          /**
           * 将flash文件绘制到页面上
           * @public
           * @return {Null}
           */
          me.render = function () {
              target = _render(createOptions);
  
              if (callBack.length > 0) {
                  baidu.each(callBack, function (funName, index) {
                      callBack[index] = _createFunName(options[funName] || new Function());
                  });
              }
              me.call('setJSFuncName', [callBack]);
          };
  
          /**
           * 返回flash状态
           * @return {Boolean}
           */
          me.isReady = function () {
              return isReady;
          };
  
          /**
           * 调用flash接口的统一入口
           * @param {String} fnName 调用的函数名
           * @param {Array} params 传入的参数组成的数组,若不许要参数，需传入空数组
           * @param {Function} [callBack] 异步调用后将返回值作为参数的调用回调函数，如无返回值，可以不传入此参数
           * @return {Null}
          */
          me.call = function (fnName, params, callBack) {
              if (!fnName) return null;
              callBack = callBack || new Function();
  
              var result = null;
  
              if (isReady) {
                  result = target.call(fnName, params);
                  callBack(result);
              } else {
                  callQueue.push({
                      fnName: fnName,
                      params: params,
                      callBack: callBack
                  });
  
                  (!timeHandle) && (timeHandle = setInterval(_check, 200));
              }
          };
  
          /**
           * 为传入的匿名函数创建函数名
           * @public
           * @param {String|Function} fun 传入的匿名函数或者函数名
           * @return {String}
           */
          me.createFunName = function (fun) {
              return _createFunName(fun);
          };
  
          /**
           * 检查flash是否ready， 并进行调用
           * @private
           * @return {Null}
           */
          function _check() {
              if (_checkReady(target)) {
                  clearInterval(timeHandle);
                  timeHandle = null;
                  _call();
  
                  isReady = true;
              }
          };
  
          /**
           * 调用之前进行压栈的函数
           * @private
           * @return {Null}
           */
          function _call() {
              _callFn(callQueue, target);
              callQueue = [];
          }
  
          autoRender && me.render();
      };
  })();
  
  /**
   * 创建flash based imageUploader
   * @class
   * @grammar baidu.flash.imageUploader(options)
   * @param {Object} createOptions 创建flash时需要的参数，请参照baidu.swf.create文档
   * @config {Object} vars 创建imageUploader时所需要的参数
   * @config {Number} vars.gridWidth 每一个预览图片所占的宽度，应该为flash寛的整除
   * @config {Number} vars.gridHeight 每一个预览图片所占的高度，应该为flash高的整除
   * @config {Number} vars.picWidth 单张预览图片的宽度
   * @config {Number} vars.picHeight 单张预览图片的高度
   * @config {String} vars.uploadDataFieldName POST请求中图片数据的key,默认值'picdata'
   * @config {String} vars.picDescFieldName POST请求中图片描述的key,默认值'picDesc'
   * @config {Number} vars.maxSize 文件的最大体积,单位'MB'
   * @config {Number} vars.compressSize 上传前如果图片体积超过该值，会先压缩
   * @config {Number} vars.maxNum:32 最大上传多少个文件
   * @config {Number} vars.compressLength 能接受的最大边长，超过该值会等比压缩
   * @config {String} vars.url 上传的url地址
   * @config {Number} vars.mode mode == 0时，是使用滚动条，mode == 1时，拉伸flash, 默认值为0
   * @see baidu.swf.createHTML
   * @param {String} backgroundUrl 背景图片路径
   * @param {String} listBacgroundkUrl 布局控件背景
   * @param {String} buttonUrl 按钮图片不背景
   * @param {String|Function} selectFileCallback 选择文件的回调
   * @param {String|Function} exceedFileCallback文件超出限制的最大体积时的回调
   * @param {String|Function} deleteFileCallback 删除文件的回调
   * @param {String|Function} startUploadCallback 开始上传某个文件时的回调
   * @param {String|Function} uploadCompleteCallback 某个文件上传完成的回调
   * @param {String|Function} uploadErrorCallback 某个文件上传失败的回调
   * @param {String|Function} allCompleteCallback 全部上传完成时的回调
   * @param {String|Function} changeFlashHeight 改变Flash的高度，mode==1的时候才有用
   */
  baidu.flash.imageUploader = baidu.flash.imageUploader || function (options) {
      var me = this,
          options = options || {},
          _flash = new baidu.flash._Base(options, [
              'selectFileCallback',
              'exceedFileCallback',
              'deleteFileCallback',
              'startUploadCallback',
              'uploadCompleteCallback',
              'uploadErrorCallback',
              'allCompleteCallback',
              'changeFlashHeight'
          ]);
      /**
       * 开始或回复上传图片
       * @public
       * @return {Null}
       */
      me.upload = function () {
          _flash.call('upload');
      };
  
      /**
       * 暂停上传图片
       * @public
       * @return {Null}
       */
      me.pause = function () {
          _flash.call('pause');
      };
      me.addCustomizedParams = function (index, obj) {
          _flash.call('addCustomizedParams', [index, obj]);
      }
  };
  
  /**
   * 操作原生对象的方法
   * @namespace baidu.object
   */
  baidu.object = baidu.object || {};
  
  /**
   * 将源对象的所有属性拷贝到目标对象中
   * @author erik
   * @name baidu.object.extend
   * @function
   * @grammar baidu.object.extend(target, source)
   * @param {Object} target 目标对象
   * @param {Object} source 源对象
   * @see baidu.array.merge
   * @remark
   *
  1.目标对象中，与源对象key相同的成员将会被覆盖。<br>
  2.源对象的prototype成员不会拷贝。
  
   * @shortcut extend
   * @meta standard
   *
   * @returns {Object} 目标对象
   */
  baidu.extend =
      baidu.object.extend = function (target, source) {
          for (var p in source) {
              if (source.hasOwnProperty(p)) {
                  target[p] = source[p];
              }
          }
  
          return target;
      };
  
  /**
   * 创建flash based fileUploader
   * @class
   * @grammar baidu.flash.fileUploader(options)
   * @param {Object} options
   * @config {Object} createOptions 创建flash时需要的参数，请参照baidu.swf.create文档
   * @config {String} createOptions.width
   * @config {String} createOptions.height
   * @config {Number} maxNum 最大可选文件数
   * @config {Function|String} selectFile
   * @config {Function|String} exceedMaxSize
   * @config {Function|String} deleteFile
   * @config {Function|String} uploadStart
   * @config {Function|String} uploadComplete
   * @config {Function|String} uploadError
   * @config {Function|String} uploadProgress
   */
  baidu.flash.fileUploader = baidu.flash.fileUploader || function (options) {
      var me = this,
          options = options || {};
  
      options.createOptions = baidu.extend({
          wmod: 'transparent'
      }, options.createOptions || {});
  
      var _flash = new baidu.flash._Base(options, [
          'selectFile',
          'exceedMaxSize',
          'deleteFile',
          'uploadStart',
          'uploadComplete',
          'uploadError',
          'uploadProgress'
      ]);
  
      _flash.call('setMaxNum', options.maxNum ? [options.maxNum] : [1]);
  
      /**
       * 设置当鼠标移动到flash上时，是否变成手型
       * @public
       * @param {Boolean} isCursor
       * @return {Null}
       */
      me.setHandCursor = function (isCursor) {
          _flash.call('setHandCursor', [isCursor || false]);
      };
  
      /**
       * 设置鼠标相应函数名
       * @param {String|Function} fun
       */
      me.setMSFunName = function (fun) {
          _flash.call('setMSFunName', [_flash.createFunName(fun)]);
      };
  
      /**
       * 执行上传操作
       * @param {String} url 上传的url
       * @param {String} fieldName 上传的表单字段名
       * @param {Object} postData 键值对，上传的POST数据
       * @param {Number|Array|null|-1} [index]上传的文件序列
       *                            Int值上传该文件
       *                            Array一次串行上传该序列文件
       *                            -1/null上传所有文件
       * @return {Null}
       */
      me.upload = function (url, fieldName, postData, index) {
          if (typeof url !== 'string' || typeof fieldName !== 'string') return null;
          if (typeof index === 'undefined') index = -1;
  
          _flash.call('upload', [url, fieldName, postData, index]);
      };
  
      /**
       * 取消上传操作
       * @public
       * @param {Number|-1} index
       */
      me.cancel = function (index) {
          if (typeof index === 'undefined') index = -1;
          _flash.call('cancel', [index]);
      };
  
      /**
       * 删除文件
       * @public
       * @param {Number|Array} [index] 要删除的index，不传则全部删除
       * @param {Function} callBack
       * */
      me.deleteFile = function (index, callBack) {
          var callBackAll = function (list) {
              callBack && callBack(list);
          };
  
          if (typeof index === 'undefined') {
              _flash.call('deleteFilesAll', [], callBackAll);
              return;
          };
  
          if (typeof index === 'Number') index = [index];
          index.sort(function (a, b) {
              return b - a;
          });
          baidu.each(index, function (item) {
              _flash.call('deleteFileBy', item, callBackAll);
          });
      };
  
      /**
       * 添加文件类型，支持macType
       * @public
       * @param {Object|Array[Object]} type {description:String, extention:String}
       * @return {Null};
       */
      me.addFileType = function (type) {
          var type = type || [[]];
  
          if (type instanceof Array) type = [type];
          else type = [[type]];
          _flash.call('addFileTypes', type);
      };
  
      /**
       * 设置文件类型，支持macType
       * @public
       * @param {Object|Array[Object]} type {description:String, extention:String}
       * @return {Null};
       */
      me.setFileType = function (type) {
          var type = type || [[]];
  
          if (type instanceof Array) type = [type];
          else type = [[type]];
          _flash.call('setFileTypes', type);
      };
  
      /**
       * 设置可选文件的数量限制
       * @public
       * @param {Number} num
       * @return {Null}
       */
      me.setMaxNum = function (num) {
          _flash.call('setMaxNum', [num]);
      };
  
      /**
       * 设置可选文件大小限制，以兆M为单位
       * @public
       * @param {Number} num,0为无限制
       * @return {Null}
       */
      me.setMaxSize = function (num) {
          _flash.call('setMaxSize', [num]);
      };
  
      /**
       * @public
       */
      me.getFileAll = function (callBack) {
          _flash.call('getFileAll', [], callBack);
      };
  
      /**
       * @public
       * @param {Number} index
       * @param {Function} [callBack]
       */
      me.getFileByIndex = function (index, callBack) {
          _flash.call('getFileByIndex', [], callBack);
      };
  
      /**
       * @public
       * @param {Number} index
       * @param {function} [callBack]
       */
      me.getStatusByIndex = function (index, callBack) {
          _flash.call('getStatusByIndex', [], callBack);
      };
  };
  
  /**
   * 使用动态script标签请求服务器资源，包括由服务器端的回调和浏览器端的回调
   * @namespace baidu.sio
   */
  baidu.sio = baidu.sio || {};
  
  /**
   *
   * @param {HTMLElement} src script节点
   * @param {String} url script节点的地址
   * @param {String} [charset] 编码
   */
  baidu.sio._createScriptTag = function (scr, url, charset) {
      scr.setAttribute('type', 'text/javascript');
      charset && scr.setAttribute('charset', charset);
      scr.setAttribute('src', url);
      document.getElementsByTagName('head')[0].appendChild(scr);
  };
  
  /**
   * 删除script的属性，再删除script标签，以解决修复内存泄漏的问题
   *
   * @param {HTMLElement} src script节点
   */
  baidu.sio._removeScriptTag = function (scr) {
      if (scr.clearAttributes) {
          scr.clearAttributes();
      } else {
          for (var attr in scr) {
              if (scr.hasOwnProperty(attr)) {
                  delete scr[attr];
              }
          }
      }
      if (scr && scr.parentNode) {
          scr.parentNode.removeChild(scr);
      }
      scr = null;
  };
  
  /**
   * 通过script标签加载数据，加载完成由浏览器端触发回调
   * @name baidu.sio.callByBrowser
   * @function
   * @grammar baidu.sio.callByBrowser(url, opt_callback, opt_options)
   * @param {string} url 加载数据的url
   * @param {Function|string} opt_callback 数据加载结束时调用的函数或函数名
   * @param {Object} opt_options 其他可选项
   * @config {String} [charset] script的字符集
   * @config {Integer} [timeOut] 超时时间，超过这个时间将不再响应本请求，并触发onfailure函数
   * @config {Function} [onfailure] timeOut设定后才生效，到达超时时间时触发本函数
   * @remark
   * 1、与callByServer不同，callback参数只支持Function类型，不支持string。
   * 2、如果请求了一个不存在的页面，callback函数在IE/opera下也会被调用，因此使用者需要在onsuccess函数中判断数据是否正确加载。
   * @meta standard
   * @see baidu.sio.callByServer
   */
  baidu.sio.callByBrowser = function (url, opt_callback, opt_options) {
      var scr = document.createElement("SCRIPT"),
          scriptLoaded = 0,
          options = opt_options || {},
          charset = options['charset'],
          callback = opt_callback || function () { },
          timeOut = options['timeOut'] || 0,
          timer;
      scr.onload = scr.onreadystatechange = function () {
          if (scriptLoaded) {
              return;
          }
  
          var readyState = scr.readyState;
          if ('undefined' == typeof readyState
              || readyState == "loaded"
              || readyState == "complete") {
              scriptLoaded = 1;
              try {
                  callback();
                  clearTimeout(timer);
              } finally {
                  scr.onload = scr.onreadystatechange = null;
                  baidu.sio._removeScriptTag(scr);
              }
          }
      };
  
      if (timeOut) {
          timer = setTimeout(function () {
              scr.onload = scr.onreadystatechange = null;
              baidu.sio._removeScriptTag(scr);
              options.onfailure && options.onfailure();
          }, timeOut);
      }
  
      baidu.sio._createScriptTag(scr, url, charset);
  };
  
  /**
   * 通过script标签加载数据，加载完成由服务器端触发回调
   * @name baidu.sio.callByServer
   * @function
   * @grammar baidu.sio.callByServer(url, callback[, opt_options])
   * @param {string} url 加载数据的url.
   * @param {Function|string} callback 服务器端调用的函数或函数名。如果没有指定本参数，将在URL中寻找options['queryField']做为callback的方法名.
   * @param {Object} opt_options 加载数据时的选项.
   * @config {string} [charset] script的字符集
   * @config {string} [queryField] 服务器端callback请求字段名，默认为callback
   * @config {Integer} [timeOut] 超时时间(单位：ms)，超过这个时间将不再响应本请求，并触发onfailure函数
   * @config {Function} [onfailure] timeOut设定后才生效，到达超时时间时触发本函数
   * @remark
   * 如果url中已经包含key为“options['queryField']”的query项，将会被替换成callback中参数传递或自动生成的函数名。
   * @meta standard
   * @see baidu.sio.callByBrowser
   */
  baidu.sio.callByServer = /**@function*/function (url, callback, opt_options) {
      var scr = document.createElement('SCRIPT'),
          prefix = 'bd__cbs__',
          callbackName,
          callbackImpl,
          options = opt_options || {},
          charset = options['charset'],
          queryField = options['queryField'] || 'callback',
          timeOut = options['timeOut'] || 0,
          timer,
          reg = new RegExp('(\\?|&)' + queryField + '=([^&]*)'),
          matches;
  
      if (baidu.lang.isFunction(callback)) {
          callbackName = prefix + Math.floor(Math.random() * 2147483648).toString(36);
          window[callbackName] = getCallBack(0);
      } else if (baidu.lang.isString(callback)) {
          callbackName = callback;
      } else {
          if (matches = reg.exec(url)) {
              callbackName = matches[2];
          }
      }
  
      if (timeOut) {
          timer = setTimeout(getCallBack(1), timeOut);
      }
      url = url.replace(reg, '\x241' + queryField + '=' + callbackName);
  
      if (url.search(reg) < 0) {
          url += (url.indexOf('?') < 0 ? '?' : '&') + queryField + '=' + callbackName;
      }
      baidu.sio._createScriptTag(scr, url, charset);
  
      /*
       * 返回一个函数，用于立即（挂在window上）或者超时（挂在setTimeout中）时执行
       */
      function getCallBack(onTimeOut) {
          /*global callbackName, callback, scr, options;*/
          return function () {
              try {
                  if (onTimeOut) {
                      options.onfailure && options.onfailure();
                  } else {
                      callback.apply(window, arguments);
                      clearTimeout(timer);
                  }
                  window[callbackName] = null;
                  delete window[callbackName];
              } catch (exception) {
              } finally {
                  baidu.sio._removeScriptTag(scr);
              }
          }
      }
  };
  
  /**
   * 通过请求一个图片的方式令服务器存储一条日志
   * @function
   * @grammar baidu.sio.log(url)
   * @param {string} url 要发送的地址.
   * @author: int08h,leeight
   */
  baidu.sio.log = function (url) {
      var img = new Image(),
          key = 'tangram_sio_log_' + Math.floor(Math.random() *
              2147483648).toString(36);
      window[key] = img;
  
      img.onload = img.onerror = img.onabort = function () {
          img.onload = img.onerror = img.onabort = null;
  
          window[key] = null;
          img = null;
      };
      img.src = url;
  };
  
  /*
   * Tangram
   * Copyright 2009 Baidu Inc. All rights reserved.
   *
   * path: baidu/json.js
   * author: erik
   * version: 1.1.0
   * date: 2009/12/02
   */
  
  /**
   * 操作json对象的方法
   * @namespace baidu.json
   */
  baidu.json = baidu.json || {};
  /*
   * Tangram
   * Copyright 2009 Baidu Inc. All rights reserved.
   *
   * path: baidu/json/parse.js
   * author: erik, berg
   * version: 1.2
   * date: 2009/11/23
   */
  
  /**
   * 将字符串解析成json对象。注：不会自动祛除空格
   * @name baidu.json.parse
   * @function
   * @grammar baidu.json.parse(data)
   * @param {string} source 需要解析的字符串
   * @remark
   * 该方法的实现与ecma-262第五版中规定的JSON.parse不同，暂时只支持传入一个参数。后续会进行功能丰富。
   * @meta standard
   * @see baidu.json.stringify,baidu.json.decode
   *
   * @returns {JSON} 解析结果json对象
   */
  baidu.json.parse = function (data) {
      //2010/12/09：更新至不使用原生parse，不检测用户输入是否正确
      return (new Function("return (" + data + ")"))();
  };
  /*
   * Tangram
   * Copyright 2009 Baidu Inc. All rights reserved.
   *
   * path: baidu/json/decode.js
   * author: erik, cat
   * version: 1.3.4
   * date: 2010/12/23
   */
  
  /**
   * 将字符串解析成json对象，为过时接口，今后会被baidu.json.parse代替
   * @name baidu.json.decode
   * @function
   * @grammar baidu.json.decode(source)
   * @param {string} source 需要解析的字符串
   * @meta out
   * @see baidu.json.encode,baidu.json.parse
   *
   * @returns {JSON} 解析结果json对象
   */
  baidu.json.decode = baidu.json.parse;
  /*
   * Tangram
   * Copyright 2009 Baidu Inc. All rights reserved.
   *
   * path: baidu/json/stringify.js
   * author: erik
   * version: 1.1.0
   * date: 2010/01/11
   */
  
  /**
   * 将json对象序列化
   * @name baidu.json.stringify
   * @function
   * @grammar baidu.json.stringify(value)
   * @param {JSON} value 需要序列化的json对象
   * @remark
   * 该方法的实现与ecma-262第五版中规定的JSON.stringify不同，暂时只支持传入一个参数。后续会进行功能丰富。
   * @meta standard
   * @see baidu.json.parse,baidu.json.encode
   *
   * @returns {string} 序列化后的字符串
   */
  baidu.json.stringify = (function () {
      /**
       * 字符串处理时需要转义的字符表
       * @private
       */
      var escapeMap = {
          "\b": '\\b',
          "\t": '\\t',
          "\n": '\\n',
          "\f": '\\f',
          "\r": '\\r',
          '"': '\\"',
          "\\": '\\\\'
      };
  
      /**
       * 字符串序列化
       * @private
       */
      function encodeString(source) {
          if (/["\\\x00-\x1f]/.test(source)) {
              source = source.replace(
                  /["\\\x00-\x1f]/g,
                  function (match) {
                      var c = escapeMap[match];
                      if (c) {
                          return c;
                      }
                      c = match.charCodeAt();
                      return "\\u00"
                          + Math.floor(c / 16).toString(16)
                          + (c % 16).toString(16);
                  });
          }
          return '"' + source + '"';
      }
  
      /**
       * 数组序列化
       * @private
       */
      function encodeArray(source) {
          var result = ["["],
              l = source.length,
              preComma, i, item;
  
          for (i = 0; i < l; i++) {
              item = source[i];
  
              switch (typeof item) {
                  case "undefined":
                  case "function":
                  case "unknown":
                      break;
                  default:
                      if (preComma) {
                          result.push(',');
                      }
                      result.push(baidu.json.stringify(item));
                      preComma = 1;
              }
          }
          result.push("]");
          return result.join("");
      }
  
      /**
       * 处理日期序列化时的补零
       * @private
       */
      function pad(source) {
          return source < 10 ? '0' + source : source;
      }
  
      /**
       * 日期序列化
       * @private
       */
      function encodeDate(source) {
          return '"' + source.getFullYear() + "-"
              + pad(source.getMonth() + 1) + "-"
              + pad(source.getDate()) + "T"
              + pad(source.getHours()) + ":"
              + pad(source.getMinutes()) + ":"
              + pad(source.getSeconds()) + '"';
      }
  
      return function (value) {
          switch (typeof value) {
              case 'undefined':
                  return 'undefined';
  
              case 'number':
                  return isFinite(value) ? String(value) : "null";
  
              case 'string':
                  return encodeString(value);
  
              case 'boolean':
                  return String(value);
  
              default:
                  if (value === null) {
                      return 'null';
                  } else if (value instanceof Array) {
                      return encodeArray(value);
                  } else if (value instanceof Date) {
                      return encodeDate(value);
                  } else {
                      var result = ['{'],
                          encode = baidu.json.stringify,
                          preComma,
                          item;
  
                      for (var key in value) {
                          if (Object.prototype.hasOwnProperty.call(value, key)) {
                              item = value[key];
                              switch (typeof item) {
                                  case 'undefined':
                                  case 'unknown':
                                  case 'function':
                                      break;
                                  default:
                                      if (preComma) {
                                          result.push(',');
                                      }
                                      preComma = 1;
                                      result.push(encode(key) + ':' + encode(item));
                              }
                          }
                      }
                      result.push('}');
                      return result.join('');
                  }
          }
      };
  })();
  /*
   * Tangram
   * Copyright 2009 Baidu Inc. All rights reserved.
   *
   * path: baidu/json/encode.js
   * author: erik, cat
   * version: 1.3.4
   * date: 2010/12/23
   */
  
  /**
   * 将json对象序列化，为过时接口，今后会被baidu.json.stringify代替
   * @name baidu.json.encode
   * @function
   * @grammar baidu.json.encode(value)
   * @param {JSON} value 需要序列化的json对象
   * @meta out
   * @see baidu.json.decode,baidu.json.stringify
   *
   * @returns {string} 序列化后的字符串
   */
  baidu.json.encode = baidu.json.stringify;